#Load packages
library(tidyverse)
library(dplyr)
library(ggplot2)
library(ggcorrplot)
library(sf)
library(gridExtra)
library(viridis) 
library(ggfx)
library(DT)
library(reactable)
library(stargazer)
library(caret)
library(plotROC)
library(ModelMetrics)

Introduction

This project seeks to explore spatial relationships between sites of protest and property damage in Minneapolis during the uprising that followed the murder of George Floyd by members of the city’s police department on May 25th, 2020. Almost immediately, protests against police brutality swept across the city, before being echoed across the world, and numbered well into the thousands.1 This period also saw the largest deployment of national guard troops in the state’s history, significant property damage, and an outpouring of mutual aid.2

This project builds on work I began with the Twin Cities chapter of the Architecture Lobby, a national architecture advocacy association, while living in Minneapolis during the summer of 2020. The project began with data collection as the city processed the protests that had just shaken its streets and the brutal murder of an unarmed Black man that had triggered them. I continued the project for my grad school GIS final in the fall of 2021 by mapping the gathered data. This project builds on this previous work by adding statistical analysis of the data and introducing new mapping methods.

As this work is ongoing, so is my own process of understanding my Whiteness in the context of being a planner and researcher interested in advancing social justice. As a result, this project may suffer from blind spots and biases I have yet to fully address.


Research Question

The research question this project seeks to address is as follows:

Were locations of damaged properties from the 2020 protests in Minneapolis over George Floyd’s murder simply a result of police station locations and protest sites, or were other factors also predictors of where protest damage occurred?

The null hypothesize is that property damage during protests was simply a result of random proximity to the flashpoints that protest sites and police stations became during that time.

The alternative hypothesis, informed by prior work, is that property type, neighorhood characteristics, and even racial bias could have been significant predictors of which properties ultimately were damaged and which werent.

The planning implications of this work relate to how and where planners can best support communities in having a voice in their cities. This is especially relevant in the U.S. context, where racially divided cities greatly outnumber their opposites and where the country’s racial minorities continue to face severe systemic oppression.


Literature Overview

In the words of the scholar Cathy Lisa Schneider:

“Riots are the last resort for those who find all other paths to justice blocked.”3

This research follows a large body of existing work on the geography and history of urban riots - one that is too great to go into here in any depth. However, this work seeks to honor Schneider’s sentiment through in depth analysis of the paths to justice that patterns of protest and property damage might reveal as missing or blocked.

Contemporary scholarship on mass protests and riots shows how public space has played a crucial role in protests across time and geography as “the battlefield on which the conflicting interests of the rich and poor are set.”4 Often, these protests are reactions against a history of “colonists and capitalists appropriating the land of the indigenous and indigent.”5 Furthermore, researchers have found that most demonstration sites fall into the same categories: “outside governmental buildings to communicate with the authorities; at centers of commercial activity to appeal to the public; to places that link them historically, culturally or morally with symbolically important events; or at places connected with a particular grievance.”6 Police stations, commercial corridors, and the various locations of the demonstrations mapped in this project all fall into these categories.

Therefore, the protests and ensuing property damage that occurred in Minneapolis in 2020 are part of a long and global lineage of the body politic seeking power through mass congregation and collective action in public space. In the context of Minneapolis however, there was a collective sense that these protests (and riots) were specifically “a challenge to the continued marginalization of Black, Indigenous, and other spaces of color through disinvestment and neglect by the state.”7

While some scholars argue for “abandoning race as a variable”,8 this project include % White. The justification for doing so is an attempt to highlight the uneven burden shared by White and BIPOC communities in Minneapolis following the protests. While fear of urban unrest spread into the suburbs, White enclaves even within city limits saw few negative outcomes.


Project Outline

The project uses a fishnet methodology to aggregate data to the level of a grid cell, and then use those grid cells for processing, model building, and analysis. The project uses binomial logit regression models to analyze the probability of the independent variables affecting a binary outcome: damaged or not damaged.

The projects workflow is as follows:

  1. Create Fishnet

  2. Engineer Features in ArcGIS (feature -> raster -> table)

  3. Import and join features in R

  4. Process and explore data

  5. Select Variables

  6. Test variables for correlation

  7. Build and Iterate Binomial Logit Models

  8. Test model prediction accuracy

  9. Interpret Results



Data

Data Sources

This project draws from the following data sources:

  • A “Damaged Properties” feature layer from the Minneapolis open data portal

  • A Police Stations feature layer from the Minneapolis open data portal

  • A Dataset of all Minneapolis parcels with use, taxable value, and primary taxpayer address from the Hennepin County open data portal

  • Median Household income and race data from the U.S. Census Bureau’s 2020 5-Year ACS


Variables

The unit of analysis is a 1/8 mile diameter fishnet grid cell.

The dependent variable is damage status (damaged vs. not).

The independent variables of interest are:
* Property type (commercial or not)
* Damaged properties
* Distance from Protest Site
* Distance from Police Station
* Absentee ownership
* Taxable property value
* % White
* Median HH Income


Data Processing

#damaged parcels
parcels_dmg <- read_sf("Processed/ParcelsWithDmg_shp/Parcels_wDmg.shp")

#all parcels in Minneapolis
#parcels_all <- read_sf("Processed/Minneapolis_Parcels_2021/Minneapolis_Parcels_2021.shp")

#msp boundary
msp_boundary <- read_sf("Raw/City_Boundary-shp/16cdbbfa-ad10-493c-afaf-52b61f2e76e42020329-1-180h9ap.whbo.shp")

msp_boundary <- msp_boundary %>% 
  st_transform(crs = 6505)

The city of Minneapolis collected a dataset of properties that were damaged during the four-day period of greatest unrest between May 25th and May 29th, 2020. The dataset lists 1182 damaged properties.

While this dataset is relatively small, to run binomial logit regressions, we need to compare damaged properties to all properties in the city, of which there are over 129,000!

Create Fishnet

To aggregate data and speed processing time, I created a grid of 1/8 mile fishnet cells that covers Minneapolis (shown below).

msp_fishnet <- st_read("Processed/msp_fishnet/msp_fishnet.shp")
## Reading layer `msp_fishnet' from data source 
##   `C:\Users\ctown\OneDrive - PennO365\Classes\Classes_Sem4_2023Spring\CPLN505_Planning by Numbers\Assignments\Final Project\Data\Processed\msp_fishnet\msp_fishnet.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 4430 features and 1 field
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 2797717 ymin: 1017704 xmax: 2833687 ymax: 1077339
## Projected CRS: NAD83(2011) / Minnesota South (ftUS)
msp_fishnet <- msp_fishnet %>%
  st_transform(crs = 6505)

map_1 <- 
ggplot()+
  geom_sf(data = msp_fishnet,
          fill = "lightgrey") +
  geom_sf(data = msp_boundary, 
          color = "black", fill = "transparent") +
  mapTheme

map_1


Feature Engineering: From Arc to R

After creating the fishnet for Minneapolis, I exported it as a shapefile for processing in ArcGIS. There, I turned each feature into a raster layer and then used the Zonal Statistics as Table tool to aggregate the values of each raster by fishnet cell. I then exported these tables of zonal statistics and brought them back into R where I joined each table with the fishnet file.

#Load in features that were engineered in arc
damaged <- read_csv("Processed/ZonalStatsTables/ZonalStats_dmgdprcls.csv") %>% 
  dplyr::select(uniqueID, SUM) %>% 
  mutate(damaged = ifelse(SUM > 3, 1, 0)) %>% 
  rename(dmg_SUM = SUM)

commercial_count <- read_csv("Processed/ZonalStatsTables/ZonalStats_commercial2.csv") %>% 
  dplyr::select(uniqueID, SUM) %>% 
  rename(cmmrcl_sum = SUM)

commercial_binary <- read_csv("Processed/ZonalStatsTables/ZonalStats_CmrclCrdr.csv") %>% 
  dplyr::select(uniqueID, CmmrclCrdr) %>% 
  rename(cmmrcl_binary = CmmrclCrdr)

dist_protest <- read_csv("Processed/ZonalStatsTables/ZonalStats_dist_protest.csv") %>% 
  dplyr::select(uniqueID, MIN) %>% 
  rename(DIST_PRTST = MIN)

dist_police <- read_csv("Processed/ZonalStatsTables/ZonalStats_dist_police.csv") %>% 
  dplyr::select(uniqueID, MIN) %>% 
  rename(DIST_POLC = MIN)

TAXVALUE <- read_csv("Processed/ZonalStatsTables/ZonalStats_taxvalue.csv") %>% 
  dplyr::select(uniqueID, MEAN) %>% 
  rename(value_mean = MEAN)

absentee <- read_csv("Processed/ZonalStatsTables/ZonalStats_AbsenteeOwners.csv") %>% 
  dplyr::select(uniqueID, SUM) %>% 
  rename(absntee_sum = SUM)

hhIncome <- read_csv("Processed/ZonalStatsTables/ZonalStats_hhincome_acs_2020.csv") %>% 
  dplyr::select(uniqueID, MEDIAN) %>% 
  rename(hhIncome_med = MEDIAN)
  
pctWhite <- read_csv("Processed/ZonalStatsTables/ZonalStats_pctWhite_acs_2020.csv") %>% 
  dplyr::select(uniqueID, MEDIAN) %>% 
  rename(pctWhite_med = MEDIAN)

#Join features with fishnet and remove NAs
dat <- msp_fishnet %>%
  mutate(uniqueID = as.integer(uniqueID)) %>% 
  left_join(commercial_count, by = "uniqueID") %>% 
  left_join(commercial_binary, by = "uniqueID") %>% 
  left_join(damaged, by = "uniqueID") %>%
  left_join(dist_protest, by = "uniqueID") %>% 
  left_join(dist_police, by = "uniqueID") %>% 
  left_join(TAXVALUE, by = "uniqueID") %>% 
  left_join(absentee, by = "uniqueID") %>% 
  left_join(hhIncome, by = "uniqueID") %>% 
  left_join(pctWhite, by = "uniqueID") %>% 
  na.omit()

#log adjust
dat$value_log <- log(dat$value_mean)
#replace infinite values with zeros
dat$value_log[sapply(dat$value_log, is.infinite)] <- 0

#display as interactive table
reactable(dat, defaultPageSize = 5)

Exploratory Analysis

Maps

Below are maps of each of the features:

#Create layer with just damaged property cells
fishnet_dmg <- dat %>% 
  filter(damaged == 1)

#Set map projection
dat <- dat %>%
  st_transform(crs = 6505)

map_2 <-
ggplot() +
  geom_sf(data = dat, aes(fill=as.factor(damaged)), alpha = 0.8, color = "transparent") +
  scale_fill_viridis(labels = c('Not Damaged', 'Damaged'),
                      alpha = .75,
                      begin = 0.05,
                      end = 0.8,
                      direction = 1,
                      discrete = TRUE,
                      option = "B") +
  geom_sf(data=msp_boundary,
          fill = "transparent",
          color = "#474747",
          size = .5) +
  geom_sf(data=fishnet_dmg,
          fill = "transparent",
          color = "white",
          size = .25) +
  labs(title ="Damaged Properties",
       fill = "Status",
       caption = "Source: opendata.minneapolismn.gov") +
  mapTheme

map_2

For damaged properties, I summed the area of damaged property by cell, and then said any cell containing more than 3 raster pixels of damaged properties is damaged, and every other cell isn’t. Therefore, after this step, damaged fishnet cells have a value of 1 and undamaged cells have a value of zero.

#Set map projection
dat <- dat %>%
  st_transform(crs = 6505)

map_6 <-
grid.arrange(ncol = 2,
ggplot() +
  geom_sf(data = dat, aes(fill=as.factor(cmmrcl_binary)), alpha = 0.8, color = "transparent") +
  scale_fill_viridis(labels = c('No', 'Yes'),
                      alpha = .75,
                      begin = 0.05,
                      end = 0.8,
                      direction = 1,
                      discrete = TRUE,
                      option = "B") +
  geom_sf(data=msp_boundary,
          fill = "transparent",
          color = "#474747",
          linewidth = .5) +
  geom_sf(data=fishnet_dmg,
          fill = "transparent",
          color = "white",
          size = .25) +
  labs(title ="On Commercial\nCorridor",
       fill = "Status",
       caption = "Source: opendata.minneapolismn.gov") +
  mapTheme,

ggplot() +
  geom_sf(data = dat, aes(fill=cmmrcl_sum), alpha = 0.8, color = "transparent") +
  scale_fill_viridis(
                     alpha = .75,
                     begin = 0,
                     end = 0.9,
                     direction = 1,
                     discrete = FALSE,
                     option = "B") +
  geom_sf(data=msp_boundary,
          fill = "transparent",
          color = "#474747",
          linewidth = .5) +
  geom_sf(data=fishnet_dmg,
          fill = "transparent",
          color = "white",
          size = .25) +
  labs(title ="Commercial Properties",
       fill = "Count",
       caption = "Source: gis-hennepin.hub.arcgis.com") +
  mapTheme
)

For cells on a commercial corridor, I used ArcGIS to set any cell that intersected with a commercial corridor to 1. To create the commercial properties variable, I simply summed the number of commercial raster pixels by fishnet cell. As a result, this variable approximates the commercial area of each cell.

dat <- dat %>%
  st_transform(crs = 6505)

map_3 <-
grid.arrange(ncol = 2,
ggplot() +
  geom_sf(data = dat, aes(fill=DIST_PRTST), alpha = 0.8, color = "transparent") +
  scale_fill_viridis(
                      alpha = .75,
                      begin = 0,
                      end = 0.9,
                      direction = -1,
                      discrete = FALSE,
                      option = "B") +
  geom_sf(data=msp_boundary,
          fill = "transparent",
          color = "#474747",
          size = .5) +
  geom_sf(data=fishnet_dmg,
          fill = "transparent",
          color = "white",
          size = .25) +
  labs(title ="Distance from Protest Sites",
       fill = "Distance (ft)",
       caption = "Source: Mapping Protest 2020") +
  mapTheme,

ggplot() +
  geom_sf(data = dat, aes(fill=DIST_POLC), alpha = 0.8, color = "transparent") +
  scale_fill_viridis(
                      alpha = .75,
                      begin = 0,
                      end = 0.9,
                      direction = -1,
                      discrete = FALSE,
                      option = "B") +
  geom_sf(data=msp_boundary,
          fill = "transparent",
          color = "#474747",
          size = .5) +
  geom_sf(data=fishnet_dmg,
          fill = "transparent",
          color = "white",
          size = .25) +
  labs(title ="Distance from Police Stations",
       fill = "Distance (ft)",
       caption = "Source: opendata.minneapolismn.gov") +
  mapTheme
)

To create the distance from protest sites and police stations variables, I assigned each cell the minimum distance it contained. This was to avoid under sampling this key metric.

dat <- dat %>%
  st_transform(crs = 6505)

map_4 <- 
grid.arrange(ncol = 2,
             
ggplot() +
  geom_sf(data = dat, aes(fill=value_log), alpha = 0.8, color = "transparent") +
  scale_fill_viridis(
                      alpha = .75,
                      begin = 0.05,
                      end = 0.85,
                      direction = 1,
                      discrete = FALSE,
                      option = "B") +
  geom_sf(data=msp_boundary,
          fill = "transparent",
          color = "#474747",
          size = .5) +
  geom_sf(data=fishnet_dmg,
          fill = "transparent",
          color = "white",
          size = .25) +
  labs(title ="Mean Taxable Value (log)",
       fill = "Value ($)",
       caption = "Source: gis-hennepin.hub.arcgis.com") +
  mapTheme,

ggplot() +
  geom_sf(data = dat, aes(fill=absntee_sum), alpha = 0.8, color = "transparent") +
  scale_fill_viridis(
                      alpha = .75,
                      begin = 0,
                      end = 0.9,
                      direction = 1,
                      discrete = FALSE,
                      option = "B") +
  geom_sf(data=msp_boundary,
          fill = "transparent",
          color = "#474747",
          size = .5) +
  geom_sf(data=fishnet_dmg,
          fill = "transparent",
          color = "white",
          size = .25) +
  labs(title ="Non MSP Resident Owned Properties",
       fill = "Count",
       caption = "Source: gis-hennepin.hub.arcgis.com") +
  mapTheme
)

To create the property value variable, I took the mean value of the raster pixels in each cell (here they’re shown log-transformed for greater clarity).

Calculating absentee ownership was a little more involved. I wanted to include this variable to test the narrative that properties with absentee owners recieved more damage than others. Unlike the other variables this proect examines, absentee ownership was not an existing field in the parcels dataset. Including this variable in the analysis required coming up with a methodology for classifying properties with owners who did not live near their properties. This project defines parcels with absentee owners as any parcel where the primary taxpayer’s address is not in Minneapolis. The code chunk below contains my method.

#Skip this
parcels_owner <- parcels_all %>% 
  dplyr::select(OBJECTID, PID, ZIP_CD, TAXPAYER_1, TAXPAYER_2, TAXPAYER_3)

parcels_owner$owner_msp <- 
  ifelse(grepl("MINNEAPOLIS", parcels_owner$TAXPAYER_2) |
         grepl("MINNEAPOLIS", parcels_owner$TAXPAYER_3) |
         grepl("MPLS", parcels_owner$TAXPAYER_2) |
         grepl("MPLS", parcels_owner$TAXPAYER_3) 
         , 1,0)

parcels_owner <- parcels_owner %>% 
  mutate(owner_mn = case_when(
    (grepl("MN", TAXPAYER_2) | grepl("MN", TAXPAYER_3)) & owner_msp != 1 ~ 1,
    TRUE ~ 0
  ))

parcels_owner <- parcels_owner %>% 
  mutate(owner_non_mn = ifelse((owner_msp == 1 | owner_mn ==1), 0, 1))

parcels_owner <- parcels_owner %>% 
  mutate(owner_non_msp = case_when(
    owner_non_mn == 1 | owner_mn == 1 & owner_msp == 0 ~ 1,
    TRUE ~ 0
  ))

write_sf(parcels_owner, "Processed/parcels_ownership/parcels_byowner.shp")
dat <- dat %>%
  st_transform(crs = 6505)

map_5 <- 
grid.arrange(ncol = 2,
             
ggplot() +
  geom_sf(data = dat, aes(fill=hhIncome_med), alpha = 0.8, color = "transparent") +
  scale_fill_viridis(alpha = .75,
                    begin = 0.05,
                    end = 0.85,
                    direction = 1,
                    discrete = FALSE,
                    option = "B") +
  geom_sf(data=msp_boundary,
          fill = "transparent",
          color = "#474747",
          size = .5) +
  geom_sf(data=fishnet_dmg,
          fill = "transparent",
          color = "white",
          size = .25) +
  labs(title ="Median Household Income",
       fill = "Value ($)",
       caption = "Source: 2020 5-Year ACS") +
  mapTheme,

ggplot() +
  geom_sf(data = dat, aes(fill=pctWhite_med), alpha = 0.8, color = "transparent") +
  scale_fill_viridis(alpha = .75,
                    begin = 0,
                    end = 0.9,
                    direction = 1,
                    discrete = FALSE,
                    option = "B") +
  geom_sf(data=msp_boundary,
          fill = "transparent",
          color = "#474747",
          size = .5) +
  geom_sf(data=fishnet_dmg,
          fill = "transparent",
          color = "white",
          size = .25) +
  labs(title ="% White Population",
       fill = "%",
       caption = "Source: 2020 5-Year ACS") +
  mapTheme
)

Finally, to incorporate census variables I set each cell equal to the median value of the raster pixels within it for both median household income and % of the populatin that identified as White in 2020.


Plots

Once I had all of the variables created and mapped, I made a series of charts to better understand the data.

#How many damaged fishent cells vs. not?
chart_2 <-
ggplot(dat, aes(x = as.factor(damaged), fill = as.factor(damaged), stat = "count")) +
  geom_bar(alpha = 0.8) +
  scale_fill_manual(values = c("#f3a108", "#4c0073"),
                    labels = c("Not Damaged", "Damaged"),
                    name = "Presence of\nDamage") +
  xlab("Damaged vs. Not") + 
  ylab("Count") +
  labs(title="Cells Containing Damage",
       subtitle = "Count of Fishnet Cells that Do and Don't Contain Damaged Properties") +
  theme_bw()

chart_2

Right away it is clear that there are far more undamaged fishnet cells than damaged ones.

cells_w_dmg <- as.numeric(sum(dat$damaged == 1))

In fact, just 213 out of the 4,430 fishnet cells (4.8%) fishnet cells contain damaged properties. That sample size is a little small, so hopefully it won’t be a problem.

#How many properties with each kind of damage?
chart_1 <-
ggplot(parcels_dmg, aes(x = dmg_lvl, fill = dmg_lvl, stat = "count")) +
  geom_bar(alpha = 0.8) +
  scale_fill_manual(values = c("#4c0073", "#f3a108", "#f27405", "#d93d04"),
                    labels = c("Destroyed", "Minor", "Moderate", "Severe"),
                    name = "Damage\nLevel") +
  xlab("Damage Level") + 
  ylab("Count") +
  labs(title="Property Damage by Level") +
  theme_bw()

chart_1

Even though I’m working with damage as a binary, I was curious about what kind of damage is most represented in the data. Plotting this reveals that:

  • 918 of them received “minor” damage

  • 216 received “moderate” damage

  • 12 received “severe” damage

  • 36 were “destroyed”

To get back on track though, how do the damaged vs. not damaged cells compare to each other for each variable of interest?

#Pivot to visualize with violin plot
dat_plotvars <- dat %>% 
  as.data.frame() %>%
    dplyr::select(damaged, cmmrcl_sum, cmmrcl_binary, DIST_PRTST, DIST_POLC, value_mean, value_log,
                  absntee_sum, hhIncome_med, pctWhite_med) %>% 
    pivot_longer(cols = -damaged)

#violin plots
chart_3 <-
ggplot(dat_plotvars) + 
     geom_violin(aes(x = as.factor(damaged), 
                  y = value, fill = as.factor(damaged))) + 
     facet_wrap(~name, scales = "free_y") +
     labs(x="Damage Status", y="Value") + 
     scale_fill_manual(values = c("#f3a108", "#4c0073"),
     labels = c("Not Damaged", "Damaged"), name = "") +
  plotTheme

chart_3

These violin plots show that some variables exhibit greater difference across damage status than others. It also shows the importance of log adjusting the value variable to be able to make meaningful comparisons by compressing outliers.


Variable Selection

Based on the data engineering and initial exploration, these are the independent variable candidates I would like to include in a binomial regression model:

  • Concentration of commercial property cmmrcl_sum
  • Location on a commercial corridor cmmrcl_binary (as a binary variable)
  • Distance from Protest Sites DIST_PRTST
  • Distance from Police Stations DIST_POLC
  • Mean property value value_mean
  • Log adjusted property value value_log
  • Concentration of Absentee Ownership absntee_sum
  • % of population that is White pctWhite_med
  • Median Household Income hhIncome_med

The exploratory analysis suggests that these variables relate to protest property damage. However, I need to make sure none of them are too correlated with the dependent variable or each other (collinear) to avoid model error.


Test for Correlation

#make matrix of variables to test
corr_vars <- dat %>% 
  as.data.frame() %>% 
  dplyr::select(-uniqueID, -geometry, -dmg_SUM) %>%
  mutate(cmmrcl_binary = as.integer(cmmrcl_binary),
         damaged = as.integer(damaged)) %>% 
  rename("Absentee Ownership" = absntee_sum,
         "Property Value" = value_mean,
         "Property Value (log)" = value_log,
         "Distance from Protest Sites" = DIST_PRTST,
         "Distance from Police Stations" = DIST_POLC,
         "Commercial Properties" = cmmrcl_sum,
         "Commercial Corridors" = cmmrcl_binary,
         "Presence of Damaged Properties" = damaged,
         "Median Household Income" = hhIncome_med,
         "Pop % White" = pctWhite_med)

#compute correlation matrix
cormatrix <- cor(corr_vars) %>% 
  round(., 2)

#plot a correlogram
chart_4 <-
ggcorrplot(cormatrix,
           method = "square",
           hc.order = FALSE,
           colors = c("#f3a108", "white", "#4c0073"),
           outline.color = "white",
           type = "lower",
           tl.cex = 9,
           lab = TRUE)

chart_4

Median Household Income is collinear with Population % White and distance from police stations. Therefore, I will include % White in models moving forward because it’s slightly more correlated with presence of damaged properties and will make for less complicated modeling.

Fortunately, the rest of these variables avoid colinearity with each other. The strongest correlation is between distance from protests and distance from police stations. This makes sense since some protests occurred at police stations. However, not all protests did so the correlation between them is still below 0.5, meaning both can stay in the model without worry.

Additionally, we see that the variables most correlated with property damage are:

  • Commercial Corridors
  • Distance from police stations
  • Distance from protest sites
  • Absentee Ownership, and
  • Property Value


Logistic Regressions

I chose to use binomial logistic regression for this assignment because it is a type of statistical model that is well suited to analyzing relationships between a binary response variable and one or more predictor variables. It estimates the probability of the response variable taking one of the two possible values (in this case damaged or not damaged) based on the values of the predictor variables.

Before making any models, I first turned the binary variables into factors. These are my depedent damage variable and the commercial corridor variable.

dat$damaged <- as.factor(dat$damaged) 
dat$cmmrcl_binary <- as.factor(dat$cmmrcl_binary)

#Convert the distance variables units from feet to miles
dat$DIST_POLC <- dat$DIST_POLC/5280
dat$DIST_PRTST <- dat$DIST_PRTST/5280

The first model includes all eight variables of interest:

  • cmmrcl_binary
  • cmmrcl_sum
  • DIST_PRTST
  • DIST_POLC
  • value_mean
  • value_log
  • absntee_sum
  • pctWhite_med

Model 1

mod1 <- glm(damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + DIST_POLC + value_mean + value_log + absntee_sum + pctWhite_med, 
            family="binomial"(link="logit"), data = dat)
summary(mod1)
## 
## Call:
## glm(formula = damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + 
##     DIST_POLC + value_mean + value_log + absntee_sum + pctWhite_med, 
##     family = binomial(link = "logit"), data = dat)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -1.7225  -0.2916  -0.1887  -0.1215   3.1884  
## 
## Coefficients:
##                       Estimate      Std. Error z value             Pr(>|z|)    
## (Intercept)    -4.154417149845  0.565657354236  -7.344    0.000000000000207 ***
## cmmrcl_sum      0.021126365004  0.003754155749   5.627    0.000000018288151 ***
## cmmrcl_binary1  1.632394371886  0.183993217997   8.872 < 0.0000000000000002 ***
## DIST_PRTST     -0.605231987247  0.159917983350  -3.785             0.000154 ***
## DIST_POLC      -0.477972179134  0.172183003939  -2.776             0.005504 ** 
## value_mean     -0.000000001540  0.000000007467  -0.206             0.836628    
## value_log       0.149801494463  0.038711561666   3.870             0.000109 ***
## absntee_sum     0.014696684007  0.004650993985   3.160             0.001578 ** 
## pctWhite_med   -0.895994498201  0.371693214700  -2.411             0.015927 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1652.2  on 3946  degrees of freedom
## Residual deviance: 1226.7  on 3938  degrees of freedom
## AIC: 1244.7
## 
## Number of Fisher Scoring iterations: 7

The results indicate:

  • The p-values indicate statistical significance for all of the variables except for value_mean.
  • The AIC of this model is 1244.7. When selecting between regression models, the model with the lower AIC better fits the data.

Automated Variable Selection

It appears that value_mean is not significant and therefore should be excluded from the model. Let’s confirm via automated variable selection with drop1.

drop1(mod1, test="Chisq")
## Single term deletions
## 
## Model:
## damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + DIST_POLC + 
##     value_mean + value_log + absntee_sum + pctWhite_med
##               Df Deviance    AIC    LRT              Pr(>Chi)    
## <none>             1226.7 1244.7                                 
## cmmrcl_sum     1   1255.4 1271.4 28.770         0.00000008152 ***
## cmmrcl_binary  1   1301.2 1317.2 74.577 < 0.00000000000000022 ***
## DIST_PRTST     1   1241.6 1257.6 14.962             0.0001097 ***
## DIST_POLC      1   1235.3 1251.3  8.606             0.0033503 ** 
## value_mean     1   1226.7 1242.7  0.042             0.8369208    
## value_log      1   1248.7 1264.7 22.064         0.00000263678 ***
## absntee_sum    1   1236.0 1252.0  9.349             0.0022309 ** 
## pctWhite_med   1   1232.4 1248.4  5.730             0.0166742 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

The drop1 results indicate that removing value_mean would not increase the model’s deviance and would actually lower its AIC, meaning it would improve the model’s fit.

Model 2

So, what changes if value_mean is excluded?

mod2 <- glm(damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + DIST_POLC + value_log + absntee_sum + pctWhite_med, 
            family="binomial"(link="logit"), data = dat)
summary(mod2)
## 
## Call:
## glm(formula = damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + 
##     DIST_POLC + value_log + absntee_sum + pctWhite_med, family = binomial(link = "logit"), 
##     data = dat)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -1.7236  -0.2923  -0.1887  -0.1221   3.1873  
## 
## Coefficients:
##                 Estimate Std. Error z value             Pr(>|z|)    
## (Intercept)    -4.110554   0.519901  -7.906  0.00000000000000265 ***
## cmmrcl_sum      0.021005   0.003709   5.663  0.00000001483524704 ***
## cmmrcl_binary1  1.632743   0.184052   8.871 < 0.0000000000000002 ***
## DIST_PRTST     -0.603839   0.159711  -3.781             0.000156 ***
## DIST_POLC      -0.476805   0.172082  -2.771             0.005592 ** 
## value_log       0.146347   0.034518   4.240  0.00002237605533143 ***
## absntee_sum     0.014661   0.004648   3.154             0.001608 ** 
## pctWhite_med   -0.899849   0.371210  -2.424             0.015347 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1652.2  on 3946  degrees of freedom
## Residual deviance: 1226.7  on 3939  degrees of freedom
## AIC: 1242.7
## 
## Number of Fisher Scoring iterations: 7

Good news, dropping value_mean decreased the AIC by 2 from Model 1’s AIC of 1244.7. This means Model 2 describes the data better than Model 1 but with 1 fewer variable.

However, pctWhite_med is still less significant than the other variables. What happens if this variable is excluded from the next model? Based on the drop1 results, the AIC should increase slightly (by 4?).

Model 3

mod3 <- glm(damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + DIST_POLC + value_log + absntee_sum, 
            family="binomial"(link="logit"), data = dat)
summary(mod3)
## 
## Call:
## glm(formula = damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + 
##     DIST_POLC + value_log + absntee_sum, family = binomial(link = "logit"), 
##     data = dat)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -1.5842  -0.2901  -0.1940  -0.1254   3.1799  
## 
## Coefficients:
##                 Estimate Std. Error z value             Pr(>|z|)    
## (Intercept)    -4.435073   0.487791  -9.092 < 0.0000000000000002 ***
## cmmrcl_sum      0.020431   0.003662   5.579         0.0000000242 ***
## cmmrcl_binary1  1.624902   0.183892   8.836 < 0.0000000000000002 ***
## DIST_PRTST     -0.568661   0.160176  -3.550             0.000385 ***
## DIST_POLC      -0.591472   0.165653  -3.571             0.000356 ***
## value_log       0.137034   0.032795   4.179         0.0000293434 ***
## absntee_sum     0.014611   0.004592   3.182             0.001462 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1652.2  on 3946  degrees of freedom
## Residual deviance: 1232.5  on 3940  degrees of freedom
## AIC: 1246.5
## 
## Number of Fisher Scoring iterations: 7

The AIC increased slightly this time (by 3.8) from Model 2’s AIC of 1242.7. Since this is a minor increase, a model without value_mean or pctWhite_med functionally describes the data as a well as a model with them.

Now all of the variables have at least a high level of significance. However, absntee_sum is less significant than the others. What happens if absntee_sum is dropped from the model?

Model 4

mod4 <- glm(damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + DIST_POLC + value_log, 
            family="binomial"(link="logit"), data = dat)
summary(mod4)
## 
## Call:
## glm(formula = damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + 
##     DIST_POLC + value_log, family = binomial(link = "logit"), 
##     data = dat)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -1.6435  -0.2900  -0.1988  -0.1316   3.1652  
## 
## Coefficients:
##                 Estimate Std. Error z value             Pr(>|z|)    
## (Intercept)    -4.650283   0.500874  -9.284 < 0.0000000000000002 ***
## cmmrcl_sum      0.023619   0.003456   6.834     0.00000000000823 ***
## cmmrcl_binary1  1.605579   0.182920   8.777 < 0.0000000000000002 ***
## DIST_PRTST     -0.546024   0.158137  -3.453             0.000555 ***
## DIST_POLC      -0.599427   0.163583  -3.664             0.000248 ***
## value_log       0.165238   0.033096   4.993     0.00000059525521 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1652.2  on 3946  degrees of freedom
## Residual deviance: 1242.0  on 3941  degrees of freedom
## AIC: 1254
## 
## Number of Fisher Scoring iterations: 7

This time, all of the variables are highly significant and the AIC has increased by 7.5 from the previous model’s AIC of 1246.5.

Before selecting a final model, was pctWhite_med actually a better predictor than its collinear pair hhIncome_med?

Model 5

mod5 <- glm(damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + DIST_POLC + value_log + absntee_sum + hhIncome_med, 
            family="binomial"(link="logit"), data = dat)
summary(mod5)
## 
## Call:
## glm(formula = damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + 
##     DIST_POLC + value_log + absntee_sum + hhIncome_med, family = binomial(link = "logit"), 
##     data = dat)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -1.6216  -0.2890  -0.1962  -0.1275   3.1884  
## 
## Coefficients:
##                    Estimate   Std. Error z value             Pr(>|z|)    
## (Intercept)    -4.533580269  0.498716451  -9.090 < 0.0000000000000002 ***
## cmmrcl_sum      0.020390578  0.003679043   5.542         0.0000000298 ***
## cmmrcl_binary1  1.616304820  0.184512252   8.760 < 0.0000000000000002 ***
## DIST_PRTST     -0.555319149  0.159801253  -3.475             0.000511 ***
## DIST_POLC      -0.645103756  0.176833786  -3.648             0.000264 ***
## value_log       0.134573871  0.032590406   4.129         0.0000363952 ***
## absntee_sum     0.014653837  0.004611012   3.178             0.001483 ** 
## hhIncome_med    0.000002489  0.000003026   0.823             0.410767    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1652.2  on 3946  degrees of freedom
## Residual deviance: 1231.8  on 3939  degrees of freedom
## AIC: 1247.8
## 
## Number of Fisher Scoring iterations: 7

Replacing pctWhite_med with hhIncome_med in the last model that it was part of (Model 2) shows that it in fact is less significant of a predictor. This fifth model’s AIC is higher than that of the model that included % White, meaning Model 2 described the data better than Model 5 does.

Time to select the final model.

Selecting a Final Model

Comparing the fit of the models with anova helps determines which model to select as the final model. Because anova can only compare nested models, Model 5 is not included. This is ok because Model 5 was the weakest model anyway.

anova(mod1, mod2, mod3, mod4, test="Chisq")
## Analysis of Deviance Table
## 
## Model 1: damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + DIST_POLC + 
##     value_mean + value_log + absntee_sum + pctWhite_med
## Model 2: damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + DIST_POLC + 
##     value_log + absntee_sum + pctWhite_med
## Model 3: damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + DIST_POLC + 
##     value_log + absntee_sum
## Model 4: damaged ~ cmmrcl_sum + cmmrcl_binary + DIST_PRTST + DIST_POLC + 
##     value_log
##   Resid. Df Resid. Dev Df Deviance Pr(>Chi)   
## 1      3938     1226.7                        
## 2      3939     1226.7 -1  -0.0424 0.836921   
## 3      3940     1232.5 -1  -5.7946 0.016076 * 
## 4      3941     1242.0 -1  -9.4673 0.002092 **
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

The Analysis of Deviance table from ANOVA compares the fit of the models against each other. The p-values indicate that Model 2 does not describe the data meaningfully differently than Model 1. However, they show that Model 3 describes the data meaningfully differently than Model 2 and Model 4 describes the data significantly differently than Model 3. Because the second model’s deviance is smaller than that of Models 3 and 4 and the same as Model 1, Model 2 describes the data the best with the fewest possible variables.

However, the deviance of all models is smaller than the null deviance of 1652.2. So, every model describes the variation in the data better than an intercept only model.

stargazer(mod1, mod2, mod3, mod4, type="html", digits = 2, single.row = FALSE, out = "C:/Users/ctown/OneDrive - PennO365/Classes/Classes_Sem4_2023Spring/CPLN505_Planning by Numbers/Assignments/Final Project/Graphics/Charts/PP_Stargazer.html")
Dependent variable:
damaged
(1) (2) (3) (4)
cmmrcl_sum 0.02*** 0.02*** 0.02*** 0.02***
(0.004) (0.004) (0.004) (0.003)
cmmrcl_binary1 1.63*** 1.63*** 1.62*** 1.61***
(0.18) (0.18) (0.18) (0.18)
DIST_PRTST -0.61*** -0.60*** -0.57*** -0.55***
(0.16) (0.16) (0.16) (0.16)
DIST_POLC -0.48*** -0.48*** -0.59*** -0.60***
(0.17) (0.17) (0.17) (0.16)
value_mean -0.00
(0.00)
value_log 0.15*** 0.15*** 0.14*** 0.17***
(0.04) (0.03) (0.03) (0.03)
absntee_sum 0.01*** 0.01*** 0.01***
(0.005) (0.005) (0.005)
pctWhite_med -0.90** -0.90**
(0.37) (0.37)
Constant -4.15*** -4.11*** -4.44*** -4.65***
(0.57) (0.52) (0.49) (0.50)
Observations 3,947 3,947 3,947 3,947
Log Likelihood -613.33 -613.36 -616.25 -620.99
Akaike Inf. Crit. 1,244.67 1,242.71 1,246.51 1,253.97
Note: p<0.1; p<0.05; p<0.01


Model 2 has the lowest AIC of all the models and all of its variables are significant. Therefore, Model 2 is selected as the final model.



Regression Interpretation

So what do these regression results mean anyway?

Coefficients

#if exp(coef) = .8:  a unit increase in X is associated with 
#a 20% decline in the odds ratio
#if exp(coef)  = 1.5:  a unit increase in X is associated with 
#a 50% increase in the odds ratio
100 * (exp(coef(mod2))-1)
##    (Intercept)     cmmrcl_sum cmmrcl_binary1     DIST_PRTST      DIST_POLC 
##     -98.360131       2.122755     411.789491     -45.329131     -37.923630 
##      value_log    absntee_sum   pctWhite_med 
##      15.759766       1.476858     -59.336876

The coefficients of the model suggest that:

  • All else equal, a one unit increase in the area of commercial properties in a fishnet cell increases the odds ratio of a cell containing damaged properties by 2.1%.

  • All else equal, the odds ratio of a cell on a commercial corridor being damaged is 411.8% higher than for a cell not on a commercial corridor.

  • All else equal, a one unit (1 mile) increase in distance from a protest site decreases the odds ratio of a cell containing damaged properties by 45.3%.

  • All else equal, a one unit (1 mile) increase in distance from a police station decreases the odds ratio of a cell containing damaged properties by 37.9%.

  • All else equal, a one unit increase in property value increases the odds ratio of a cell containing damaged properties by 0.2% (15.8/100 because the variable is log-adjusted).

  • All else equal, a unit increase in the presence of absentee owned properties increases the odds ratio of a cell containing damaged properties by 1.5%.

  • All else equal, a unit (1%) increase in the share of White residents in a cell decreases the odds ratio of a cell containing damaged properties by 59.3%.

While all of these variables are significant, it is worth noting the variables with the largest coefficients. These are presence of a commercial corridor cmmrcl_binary1, distance from a protest site DIST_PRTST or police station DIST_POLC, and the share of population in a given cell that’s White pctWhite_med.

It is also important to note that the coefficient for the intercept is quite large, meaning there is still much of the variation in the data that the selected variables do not explain.

Ultimately, the most important result of running these models is the ability to reject the null hypothesis that a model that only includes distance from protest sites and police stations predicts protest property damage better than a model that includes other variables.


Prediction Accuracy

#Create dataframe to hold predicted probabilities
pred <- as.data.frame(fitted(mod2))
pred <- mutate(pred, "obs" = dat$damaged)
pred <- rename(pred, "prob" = "fitted(mod2)")
pred <- mutate(pred, "pred" = ifelse(prob < 0.5, 0, 1)) #if predicted probabilities are <0.5, then classify as zero, otherwise classify as 1

#Create confusion matrix
caret::confusionMatrix(reference = as.factor(pred$obs), 
                       data = as.factor(pred$pred), 
                       positive = "1")
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction    0    1
##          0 3709  186
##          1   26   26
##                                              
##                Accuracy : 0.9463             
##                  95% CI : (0.9388, 0.9531)   
##     No Information Rate : 0.9463             
##     P-Value [Acc > NIR] : 0.5183             
##                                              
##                   Kappa : 0.1796             
##                                              
##  Mcnemar's Test P-Value : <0.0000000000000002
##                                              
##             Sensitivity : 0.122642           
##             Specificity : 0.993039           
##          Pos Pred Value : 0.500000           
##          Neg Pred Value : 0.952246           
##              Prevalence : 0.053712           
##          Detection Rate : 0.006587           
##    Detection Prevalence : 0.013175           
##       Balanced Accuracy : 0.557840           
##                                              
##        'Positive' Class : 1                  
## 

Calculating our model’s prediction accuracy gives us an accuracy rate of 95% - pretty good! But is it too good?

We see that the model considerably under predicts the likelihood of a fishnet cell containing damaged properties. So the accuracy rate says more about the small sample size of damaged properties than the generalizability of the model.

Mapping Predictions

ctrl <- trainControl(method = "cv", 
                     number = 100, 
                     savePredictions = TRUE)

dmgFit <- train(as.factor(damaged) ~ .,
               data = dat %>% 
                 as.data.frame() %>%
                 dplyr::select(damaged, cmmrcl_sum, cmmrcl_binary, DIST_PRTST, DIST_POLC, value_log,
                absntee_sum, pctWhite_med) %>% 
               na.omit(),
               method="glm", family="binomial",
               trControl = ctrl)
dmgFit
#inundFit is our model trained to predict using the binomial logistic regression, or glm, method. 
dat_map <- dat %>% 
  dplyr::select(uniqueID, damaged, cmmrcl_sum, cmmrcl_binary, DIST_PRTST, DIST_POLC, value_log,
                absntee_sum, pctWhite_med, geometry)

allPredictions <- 
  predict(dmgFit, dat, type="prob")[,2]
  
dat_pred <- 
  cbind(dat_map, allPredictions) %>%
  mutate(allPredictions = round(allPredictions * 100)) 

dat_pred <- dat_pred %>%
  mutate(confResult=case_when(allPredictions < 50 & damaged==0 ~ "True Negative",
                              allPredictions >= 50 & damaged==1 ~ "True Positive",
                              allPredictions < 50 & damaged==1 ~ "False Negative",
                              allPredictions >= 50 & damaged==0 ~ "False Positive"))
dat_pred <- dat_pred %>%
  st_transform(crs = 6505)

grid.arrange(ncol = 2,
 ggplot() + 
    geom_sf(data=dat_pred, aes(fill=allPredictions), 
            colour=NA) +
      scale_fill_viridis(
                      alpha = .8,
                      begin = 0,
                      end = 0.9,
                      direction = 1,
                      discrete = FALSE,
                      option = "B",
                      name="Predicted\nProbabilities (%)") +
  labs(title="Predicted Probability of Property Damage",
       subtitle = "Based on a Logistic Regression Model") +
     mapTheme,
 
 ggplot()+
  geom_sf(data=dat_pred,
          aes(fill = confResult), color = "transparent", alpha = .8) +
  scale_fill_manual(values = c("#6B186EFF", "#CC4248FF", "#000004FF", "#FCA50AFF"),
                    name="Outcomes")+
  labs(title="Confusion Metrics",
       subtitle = "Based on a Probability >= 50%") +
  mapTheme
)

Mapping where and how well the model predicts protest property damage shows that how the cutoff for prediction accuracy is defined is very important. The map on the left of predicted probabilities seems to closely reflect the actual (or observed) patterns of property damage. However, mapping the confusion metrics on the right with a cutoff of 50% probability counts many of the cells that are highlighted in orange on the lefthand map as false negatives.

A 50% probability threshold is a reasonable threshold for prediction however. Since it is unwise to count cells with a less than 50% probability of being damaged as “likely” to be damaged.

These maps visually reinforce the conclusion of the confusion matrix. Namely, that while the model does capture basic patterns of protest property damage based on the independent variables included in it, it is still not accurately predicting overall. This shows that more variables and further testing are needed to better understand the quantitative relationships between protest property damage and factors related to land use and socioeconomic geographic traits.


Limitations

The fishnet methdology speeds processing, but sacrifices precision and makes interpreting the model’s results somewhat convoluted. For example, with the fishnet approach it is not possible to create a true binary variable for commercial vs. non-commercial properties as it would be if simply running regressions on the parcels themselves. Instead, the area of damaged properties had to be summed by fishnet grid cell as an approximation.

In another iteration of the project, it would be interesting to see if having smaller grid cells could improve the results. For example, a diameter of 160’ would give four times the number of cells. It would be interesting to see if R could still efficiently process a dataframe of 16,000. This would be a big increase from the 4,000 used in this project, but would still be a significantly smaller dataset than the 130,000 parcels within Minneapolis city limits.

Another limitation of this study is the course definition of absentee ownership. Ideally, the absentee ownership variable would be able to account for more nuance than the simple distinction of whether or not the primary taxpayer’s address was in city boundaries. Ideally, a property’s distance from its primary taxpayer would be used instead. This would capture a much more detailed and consistent relationship. However, doing so for every parcel in Minneapolis exceeded the time and processing power available for this project.

Now that this project has established a significant relationship between damaged properties and commercial land use, a logical next step is to examine which kinds of businesses were most damaged. Not having business type data at the property parcel level is a limitation of this study.

The large coefficient of the intercept highlights that more variables are necessary to accurately model the data. Other variables to include in future work, in addition to business type, are more rich socioeconomic and land-use descriptors. For example, is the importance of commercial corridors in the model because of density of stores or something else? And, how might the identity of affected areas, their relationship to the city’s power structures, and the communities that watched over them relate to level of damage received? Mobility could also be an important factor. Might transit access and walkability have positively correlated with protest damage?

Finally, this is not a story of numbers. Ideally a project like this would be providing data that supports or adds nuance to a robust qualitative research project that centers the stories of those most affected by George Floyd’s murder at the hands of the Minneapolis Police Department and the destruction that followed.


Planning Implications

This project shows that the property damage related to the protests against George Floyd’s murder in Minneapolis in 2020 was not simply a matter of proximity to protest sites. Instead, it indicates that commercial corridors were significant locations of protest damage and protest damage in White enclaves was conspiciously absent.

While the presence of commercial properties was related to protest damage with statistical significance, it is noteworthy that location on a commercial corridor was a much stronger predictor of damage. This suggests that perception of public space may have a stronger effect than its actual use. It also emphasizes that commercial corridors are key nodes of public expression and identity in urban environments. In particular, the results of this research suggest that when protesters struggle for agency in a capitalist society where commerce and power are deeply interwoven, the commercial corridors of society itself are likely to become contested ground. Therefore, planners would do well to support initiatives that strengthen community identity and provide spaces for movement building on commercial corridors. Arguably, the Minneapolis public did not have enough constructive avenues for city leaders to hear and respond to their anger in 2020. This research suggests that commercial corridors are key sites for city planners to provide or encourage accessible and meaningful connections between the public and civic power structures.

Similarly, the fact that the share of White population in an area had a significant negative relationship with protest damage speaks to the identity of a place being an important factor during the Minneapolis protests of 2020. It lends statistical weight to the idea that the racial and economic segregation of U.S. cities that has historically concentrated affluence and power in largely White neighborhoods may also have concentrated protests within the city’s economically or racially marginalized communities. It is important to recognize that White and BIPOC Minneapolitans did not equally suffer the consequences of destruction following the protests. Therefore, city planners have an imperative to concentrate efforts at rebuilding and reconciliation in areas with low shares of White residents.

While the coefficients for absentee ownership and property value were small, they show that these were also statistically significant factors during the protests. The fact that absentee ownership is a statistically significant variable lends credence to a common narrative among protestors that property damage was an expression of anger and frustration targeted at capitalist power structures rather than local business owners. The slight correlation between property damage and high property value further supports this hypothesis. Together, these factors suggest that supporting and increasing access to local business ownership could have a long-term stabilizing effect in cities. Increasing access to local ownership of high value property perhaps even more so.

These observations are meant to be exploratory rather than definitive. I hope this piece can serve as a jumping off point for those continuing the study of spatial characteristics of protest in Minneapolis.



References

  1. Boone, Anna. “One Week in Minneapolis.” Star Tribune. June 3, 2020.
    https://www.startribune.com/george-floyd-death-ignited-protests-far-beyond-minneapolis-police-minnesota/569930771/.

  2. Bakst, Brian. “Guard Mobilized Quickly, Adjusted on Fly for Floyd Unrest.” MPR News, July 10, 2020. https://www.mprnews.org/story/2020/07/10/guard-mobilized-quickly-adjusted-on-fly-for-floyd-unrest.

  3. Schneider, Cathy Lisa. 2017. Police Power and Race Riots: Urban Unrest in Paris and New York. Reprint edition. Philadelphia, Pa: University of Pennsylvania Press.

  4. Springer, Simon. “Public Space as Emancipation: Meditations on Anarchism, Radical Democracy, Neoliberalism and Violence.” Antipode 43, no. 2 (2011): 525–62. https://doi.org/10.1111/j.1467-8330.2010.00827.x.

  5. McDonagh, Briony, and Carl J. Griffin. “Occupy! Historical Geographies of Property, Protest and the Commons, 1500–1850.” Journal of Historical Geography 53 (July 1, 2016): 1–10. https://doi.org/10.1016/j.jhg.2016.03.002.

  6. Salmenkari, Taru. “Geography of Protest: Places of Demonstration in Buenos Aires and Seoul.” Urban Geography 30, no. 3 (April 1, 2009): 239–60. https://doi.org/10.2747/0272-3638.30.3.239.

  7. Smiles, Deondre. “George Floyd, Minneapolis, and Spaces of Hope and Liberation.” Dialogues in Human Geography 11, no. 2 (July 1, 2021): 165–69. https://doi.org/10.1177/20438206211027466.

  8. Fullilove, M T. “Comment: Abandoning ‘Race’ as a Variable in Public Health Research–an Idea Whose Time Has Come.” American Journal of Public Health 88, no. 9 (September 1998): 1297–98.

LS0tDQp0aXRsZTogIlByb3Rlc3QgJiBQcm9wZXJ0eSINCnN1YnRpdGxlOiAiQ1BMTjUwNSBGaW5hbCBQcm9qZWN0Ig0KYXV0aG9yOiAiQ2hhcmxpZSBUb3duc2xleSINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiAzDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIGhpZ2hsaWdodDogYnJlZXplZGFyaw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkgDQprbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9ICJDOi9Vc2Vycy9jdG93bi9PbmVEcml2ZSAtIFBlbm5PMzY1L0NsYXNzZXMvQ2xhc3Nlc19TZW00XzIwMjNTcHJpbmcvQ1BMTjUwNV9QbGFubmluZyBieSBOdW1iZXJzL0Fzc2lnbm1lbnRzL0ZpbmFsIFByb2plY3QvRGF0YSIpDQpybShsaXN0PWxzKCkpDQoNCm9wdGlvbnMoc2NpcGVuID0gOTk5KSAjdHVybiBvZmYgc2NpZW50aWZpYyBub3RhdGlvbg0KYGBgDQoNCmBgYHtyIHBhY2thZ2VzLCByZXN1bHRzPSdoaWRlJ30NCiNMb2FkIHBhY2thZ2VzDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdnY29ycnBsb3QpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShncmlkRXh0cmEpDQpsaWJyYXJ5KHZpcmlkaXMpIA0KbGlicmFyeShnZ2Z4KQ0KbGlicmFyeShEVCkNCmxpYnJhcnkocmVhY3RhYmxlKQ0KbGlicmFyeShzdGFyZ2F6ZXIpDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShwbG90Uk9DKQ0KbGlicmFyeShNb2RlbE1ldHJpY3MpDQpgYGANCg0KYGBge3IgdGhlbWVzIGFuZCBjb2xvcnMsIHJlc3VsdHMgPSAiaGlkZSIsIGVjaG89RkFMU0V9DQoNCm1hcFRoZW1lIDwtIHRoZW1lKHBsb3QudGl0bGUgPWVsZW1lbnRfdGV4dChzaXplPTEyKSwNCiAgICAgICAgICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04KSwNCiAgICAgICAgICAgICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksDQogICAgICAgICAgICAgICAgICBheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3I9ZWxlbWVudF9saW5lKGNvbG91ciA9ICd0cmFuc3BhcmVudCcpLA0KICAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIiwgDQogICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLA0KICAgICAgICAgICAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMSwgMSwgMSwgMSwgJ2NtJyksDQogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMSwgImNtIiksIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDAuMiwgImNtIikpDQoNCnBsb3RUaGVtZSA8LSB0aGVtZSgNCiAgcGxvdC50aXRsZSA9ZWxlbWVudF90ZXh0KHNpemU9MTIpLA0KICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OCksDQogIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksDQogIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICMgU2V0IHRoZSBlbnRpcmUgY2hhcnQgcmVnaW9uIHRvIGJsYW5rDQogIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLA0KICBwbG90LmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLA0KICAjcGFuZWwuYm9yZGVyPWVsZW1lbnRfcmVjdChjb2xvdXI9IiNGMEYwRjAiKSwNCiAgIyBGb3JtYXQgdGhlIGdyaWQNCiAgcGFuZWwuZ3JpZC5tYWpvcj1lbGVtZW50X2xpbmUoY29sb3VyPSIjRDBEMEQwIixzaXplPS43NSksDQogIGF4aXMudGlja3M9ZWxlbWVudF9ibGFuaygpKQ0KDQojR2V0IGluZGl2aWR1YWwgdmlyaWRpcyBjb2xvcnMNCmxpYnJhcnkoc2NhbGVzKQ0KVmNvbG9ycyA9ICB2aXJpZGlzKDIsIG9wdGlvbiA9ICJCIiwgYmVnaW4gPSAwLCBlbmQgPSAwLjgpDQoNCiNDb2xvciBQYWxldHRlcw0KcGFsZXR0ZTEgPC0gIiNGQ0E1MEFGRiINCnBhbGV0dGUyIDwtIGMoIiMwODA1MURGRiIsICIjRkNBNTBBRkYiKQ0KcGFsZXR0ZTMgPC0gYygiIzA4MDUxREZGIiwgIiM5RTI5NjRGRiIsICIjRkNBNTBBRkYiKQ0KcGFsZXR0ZTQgPC0gYygiIzA4MDUxREZGIiwgIiM2QjE4NkVGRiIsICIjQ0M0MjQ4RkYiLCAiI0ZDQTUwQUZGIikNCnBhbGV0dGU1IDwtIGMoIiMwODA1MURGRiIsICIjNTIwRTZERkYiLCAiIzlFMjk2NEZGIiwgIiNFMDU1MzZGRiIsICIjRkNBNTBBRkYiKQ0KDQpgYGANCg0KIyBJbnRyb2R1Y3Rpb24NCg0KVGhpcyBwcm9qZWN0IHNlZWtzIHRvIGV4cGxvcmUgc3BhdGlhbCByZWxhdGlvbnNoaXBzIGJldHdlZW4gc2l0ZXMgb2YgcHJvdGVzdCBhbmQgcHJvcGVydHkgZGFtYWdlIGluIE1pbm5lYXBvbGlzIGR1cmluZyB0aGUgdXByaXNpbmcgdGhhdCBmb2xsb3dlZCB0aGUgbXVyZGVyIG9mIEdlb3JnZSBGbG95ZCBieSBtZW1iZXJzIG9mIHRoZSBjaXR54oCZcyBwb2xpY2UgZGVwYXJ0bWVudCBvbiBNYXkgMjV0aCwgMjAyMC4gQWxtb3N0IGltbWVkaWF0ZWx5LCBwcm90ZXN0cyBhZ2FpbnN0IHBvbGljZSBicnV0YWxpdHkgc3dlcHQgYWNyb3NzIHRoZSBjaXR5LCBiZWZvcmUgYmVpbmcgZWNob2VkIGFjcm9zcw0KdGhlIHdvcmxkLCBhbmQgbnVtYmVyZWQgd2VsbCBpbnRvIHRoZSB0aG91c2FuZHMuXjFeIFRoaXMgcGVyaW9kIGFsc28gc2F3IHRoZSBsYXJnZXN0IGRlcGxveW1lbnQgb2YgbmF0aW9uYWwgZ3VhcmQgdHJvb3BzIGluIHRoZSBzdGF0ZeKAmXMgaGlzdG9yeSwgc2lnbmlmaWNhbnQgcHJvcGVydHkgZGFtYWdlLCBhbmQgYW4gb3V0cG91cmluZyBvZiBtdXR1YWwgYWlkLl4yXg0KDQpUaGlzIHByb2plY3QgYnVpbGRzIG9uIHdvcmsgSSBiZWdhbiB3aXRoIHRoZSBUd2luIENpdGllcyBjaGFwdGVyIG9mIHRoZSBBcmNoaXRlY3R1cmUgTG9iYnksIGEgbmF0aW9uYWwgYXJjaGl0ZWN0dXJlIGFkdm9jYWN5IGFzc29jaWF0aW9uLCB3aGlsZSBsaXZpbmcgaW4gTWlubmVhcG9saXMgZHVyaW5nIHRoZSBzdW1tZXIgb2YgMjAyMC4gVGhlIHByb2plY3QgYmVnYW4gd2l0aCBkYXRhIGNvbGxlY3Rpb24gYXMgdGhlIGNpdHkgcHJvY2Vzc2VkIHRoZSBwcm90ZXN0cyB0aGF0IGhhZCBqdXN0IHNoYWtlbiBpdHMgc3RyZWV0cyBhbmQgdGhlIGJydXRhbCBtdXJkZXIgb2YgYW4gdW5hcm1lZCBCbGFjayBtYW4gdGhhdCBoYWQgdHJpZ2dlcmVkIHRoZW0uIEkgY29udGludWVkIHRoZSBwcm9qZWN0IGZvciBteSBncmFkIHNjaG9vbCBHSVMgZmluYWwgaW4gdGhlIGZhbGwgb2YgMjAyMSBieSBtYXBwaW5nIHRoZSBnYXRoZXJlZCBkYXRhLiBUaGlzIHByb2plY3QgYnVpbGRzIG9uIHRoaXMgcHJldmlvdXMgd29yayBieSBhZGRpbmcgc3RhdGlzdGljYWwgYW5hbHlzaXMgb2YgdGhlIGRhdGEgYW5kIGludHJvZHVjaW5nIG5ldyBtYXBwaW5nIG1ldGhvZHMuDQoNCkFzIHRoaXMgd29yayBpcyBvbmdvaW5nLCBzbyBpcyBteSBvd24gcHJvY2VzcyBvZiB1bmRlcnN0YW5kaW5nIG15IFdoaXRlbmVzcyBpbiB0aGUgY29udGV4dCBvZiBiZWluZyBhIHBsYW5uZXIgYW5kIHJlc2VhcmNoZXIgaW50ZXJlc3RlZCBpbiBhZHZhbmNpbmcgc29jaWFsIGp1c3RpY2UuIEFzIGEgcmVzdWx0LCB0aGlzIHByb2plY3QgbWF5IHN1ZmZlciBmcm9tIGJsaW5kIHNwb3RzIGFuZCBiaWFzZXMgSSBoYXZlIHlldCB0byBmdWxseSBhZGRyZXNzLg0KDQo8YnI+DQoNCiMjIFJlc2VhcmNoIFF1ZXN0aW9uDQoNClRoZSByZXNlYXJjaCBxdWVzdGlvbiB0aGlzIHByb2plY3Qgc2Vla3MgdG8gYWRkcmVzcyBpcyBhcyBmb2xsb3dzOg0KDQo+V2VyZSBsb2NhdGlvbnMgb2YgZGFtYWdlZCBwcm9wZXJ0aWVzIGZyb20gdGhlIDIwMjAgcHJvdGVzdHMgaW4gTWlubmVhcG9saXMgb3ZlciBHZW9yZ2UgRmxveWTigJlzIG11cmRlciBzaW1wbHkgYSByZXN1bHQgb2YgcG9saWNlIHN0YXRpb24gbG9jYXRpb25zIGFuZCBwcm90ZXN0IHNpdGVzLCBvciB3ZXJlIG90aGVyIGZhY3RvcnMgYWxzbyBwcmVkaWN0b3JzIG9mIHdoZXJlIHByb3Rlc3QgZGFtYWdlIG9jY3VycmVkPw0KDQpUaGUgbnVsbCBoeXBvdGhlc2l6ZSBpcyB0aGF0IHByb3BlcnR5IGRhbWFnZSBkdXJpbmcgcHJvdGVzdHMgd2FzIHNpbXBseSBhIHJlc3VsdCBvZiByYW5kb20gcHJveGltaXR5IHRvIHRoZSBmbGFzaHBvaW50cyB0aGF0IHByb3Rlc3Qgc2l0ZXMgYW5kIHBvbGljZSBzdGF0aW9ucyBiZWNhbWUgZHVyaW5nIHRoYXQgdGltZS4NCg0KVGhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMsIGluZm9ybWVkIGJ5IHByaW9yIHdvcmssIGlzIHRoYXQgcHJvcGVydHkgdHlwZSwgbmVpZ2hvcmhvb2QgY2hhcmFjdGVyaXN0aWNzLCBhbmQgZXZlbiByYWNpYWwgYmlhcyBjb3VsZCBoYXZlIGJlZW4gc2lnbmlmaWNhbnQgcHJlZGljdG9ycyBvZiB3aGljaCBwcm9wZXJ0aWVzIHVsdGltYXRlbHkgd2VyZSBkYW1hZ2VkIGFuZCB3aGljaCB3ZXJlbnQuDQoNClRoZSBwbGFubmluZyBpbXBsaWNhdGlvbnMgb2YgdGhpcyB3b3JrIHJlbGF0ZSB0byBob3cgYW5kIHdoZXJlIHBsYW5uZXJzIGNhbiBiZXN0IHN1cHBvcnQgY29tbXVuaXRpZXMgaW4gaGF2aW5nIGEgdm9pY2UgaW4gdGhlaXIgY2l0aWVzLiBUaGlzIGlzIGVzcGVjaWFsbHkgcmVsZXZhbnQgaW4gdGhlIFUuUy4gY29udGV4dCwgd2hlcmUgcmFjaWFsbHkgZGl2aWRlZCBjaXRpZXMgZ3JlYXRseSBvdXRudW1iZXIgdGhlaXIgb3Bwb3NpdGVzIGFuZCB3aGVyZSB0aGUgY291bnRyeSdzIHJhY2lhbCBtaW5vcml0aWVzIGNvbnRpbnVlIHRvIGZhY2Ugc2V2ZXJlIHN5c3RlbWljIG9wcHJlc3Npb24uDQoNCjxicj4NCg0KIyMgTGl0ZXJhdHVyZSBPdmVydmlldw0KDQpJbiB0aGUgd29yZHMgb2YgdGhlIHNjaG9sYXIgQ2F0aHkgTGlzYSBTY2huZWlkZXI6ICANCg0KPiJSaW90cyBhcmUgdGhlIGxhc3QgcmVzb3J0IGZvciB0aG9zZSB3aG8gZmluZCBhbGwgb3RoZXIgcGF0aHMgdG8ganVzdGljZSBibG9ja2VkLiJeM14NCg0KVGhpcyByZXNlYXJjaCBmb2xsb3dzIGEgbGFyZ2UgYm9keSBvZiBleGlzdGluZyB3b3JrIG9uIHRoZSBnZW9ncmFwaHkgYW5kIGhpc3Rvcnkgb2YgdXJiYW4gcmlvdHMgLSBvbmUgdGhhdCBpcyB0b28gZ3JlYXQgdG8gZ28gaW50byBoZXJlIGluIGFueSBkZXB0aC4gSG93ZXZlciwgdGhpcyB3b3JrIHNlZWtzIHRvIGhvbm9yIFNjaG5laWRlcidzIHNlbnRpbWVudCB0aHJvdWdoIGluIGRlcHRoIGFuYWx5c2lzIG9mIHRoZSBwYXRocyB0byBqdXN0aWNlIHRoYXQgcGF0dGVybnMgb2YgcHJvdGVzdCBhbmQgcHJvcGVydHkgZGFtYWdlIG1pZ2h0IHJldmVhbCBhcyBtaXNzaW5nIG9yIGJsb2NrZWQuDQoNCkNvbnRlbXBvcmFyeSBzY2hvbGFyc2hpcCBvbiBtYXNzIHByb3Rlc3RzIGFuZCByaW90cyBzaG93cyBob3cgcHVibGljIHNwYWNlIGhhcyBwbGF5ZWQgYSBjcnVjaWFsIHJvbGUgaW4gcHJvdGVzdHMgYWNyb3NzIHRpbWUgYW5kIGdlb2dyYXBoeSBhcyDigJx0aGUgYmF0dGxlZmllbGQgb24gd2hpY2ggdGhlIGNvbmZsaWN0aW5nIGludGVyZXN0cyBvZiB0aGUgcmljaCBhbmQgcG9vciBhcmUgc2V0LuKAnV40XiBPZnRlbiwgdGhlc2UgcHJvdGVzdHMgYXJlIHJlYWN0aW9ucyBhZ2FpbnN0IGEgaGlzdG9yeSBvZiDigJxjb2xvbmlzdHMgYW5kIGNhcGl0YWxpc3RzIGFwcHJvcHJpYXRpbmcgdGhlIGxhbmQgb2YgdGhlIGluZGlnZW5vdXMgYW5kIGluZGlnZW50LuKAnV41XiBGdXJ0aGVybW9yZSwgcmVzZWFyY2hlcnMgaGF2ZSBmb3VuZCB0aGF0IG1vc3QgZGVtb25zdHJhdGlvbiBzaXRlcyBmYWxsIGludG8gdGhlIHNhbWUgY2F0ZWdvcmllczog4oCcb3V0c2lkZSBnb3Zlcm5tZW50YWwgYnVpbGRpbmdzIHRvIGNvbW11bmljYXRlIHdpdGggdGhlIGF1dGhvcml0aWVzOyBhdCBjZW50ZXJzIG9mIGNvbW1lcmNpYWwgYWN0aXZpdHkgdG8gYXBwZWFsIHRvIHRoZSBwdWJsaWM7IHRvIHBsYWNlcyB0aGF0IGxpbmsgdGhlbSBoaXN0b3JpY2FsbHksIGN1bHR1cmFsbHkgb3IgbW9yYWxseSB3aXRoIHN5bWJvbGljYWxseSBpbXBvcnRhbnQgZXZlbnRzOyBvciBhdCBwbGFjZXMgY29ubmVjdGVkIHdpdGggYSBwYXJ0aWN1bGFyIGdyaWV2YW5jZS7igJ1eNl4gIFBvbGljZSBzdGF0aW9ucywgY29tbWVyY2lhbCBjb3JyaWRvcnMsIGFuZCB0aGUgdmFyaW91cyBsb2NhdGlvbnMgb2YgdGhlIGRlbW9uc3RyYXRpb25zIG1hcHBlZCBpbiB0aGlzIHByb2plY3QgYWxsIGZhbGwgaW50byB0aGVzZSBjYXRlZ29yaWVzLg0KDQpUaGVyZWZvcmUsIHRoZSBwcm90ZXN0cyBhbmQgZW5zdWluZyBwcm9wZXJ0eSBkYW1hZ2UgdGhhdCBvY2N1cnJlZCBpbiBNaW5uZWFwb2xpcyBpbiAyMDIwIGFyZSBwYXJ0IG9mIGEgbG9uZyBhbmQgZ2xvYmFsIGxpbmVhZ2Ugb2YgdGhlIGJvZHkgcG9saXRpYyBzZWVraW5nIHBvd2VyIHRocm91Z2ggbWFzcyBjb25ncmVnYXRpb24gYW5kIGNvbGxlY3RpdmUgYWN0aW9uIGluIHB1YmxpYyBzcGFjZS4gSW4gdGhlIGNvbnRleHQgb2YgTWlubmVhcG9saXMgaG93ZXZlciwgdGhlcmUgd2FzIGEgY29sbGVjdGl2ZSBzZW5zZSB0aGF0IHRoZXNlIHByb3Rlc3RzIChhbmQgcmlvdHMpIHdlcmUgc3BlY2lmaWNhbGx5IOKAnGEgY2hhbGxlbmdlIHRvIHRoZSBjb250aW51ZWQgbWFyZ2luYWxpemF0aW9uIG9mIEJsYWNrLCBJbmRpZ2Vub3VzLCBhbmQgb3RoZXIgc3BhY2VzIG9mIGNvbG9yIHRocm91Z2ggZGlzaW52ZXN0bWVudCBhbmQgbmVnbGVjdCBieSB0aGUgc3RhdGUu4oCdXjdeDQoNCldoaWxlIHNvbWUgc2Nob2xhcnMgYXJndWUgZm9yICJhYmFuZG9uaW5nIHJhY2UgYXMgYSB2YXJpYWJsZSIsXjheIHRoaXMgcHJvamVjdCBpbmNsdWRlICUgV2hpdGUuIFRoZSBqdXN0aWZpY2F0aW9uIGZvciBkb2luZyBzbyBpcyBhbiBhdHRlbXB0IHRvIGhpZ2hsaWdodCB0aGUgdW5ldmVuIGJ1cmRlbiBzaGFyZWQgYnkgV2hpdGUgYW5kIEJJUE9DIGNvbW11bml0aWVzIGluIE1pbm5lYXBvbGlzIGZvbGxvd2luZyB0aGUgcHJvdGVzdHMuIFdoaWxlIGZlYXIgb2YgdXJiYW4gdW5yZXN0IHNwcmVhZCBpbnRvIHRoZSBzdWJ1cmJzLCBXaGl0ZSBlbmNsYXZlcyBldmVuIHdpdGhpbiBjaXR5IGxpbWl0cyBzYXcgZmV3IG5lZ2F0aXZlIG91dGNvbWVzLg0KDQo8YnI+DQoNCiMjIFByb2plY3QgT3V0bGluZQ0KDQpUaGUgcHJvamVjdCB1c2VzIGEgZmlzaG5ldCBtZXRob2RvbG9neSB0byBhZ2dyZWdhdGUgZGF0YSB0byB0aGUgbGV2ZWwgb2YgYSBncmlkIGNlbGwsIGFuZCB0aGVuIHVzZSB0aG9zZSBncmlkIGNlbGxzIGZvciBwcm9jZXNzaW5nLCBtb2RlbCBidWlsZGluZywgYW5kIGFuYWx5c2lzLiAgVGhlIHByb2plY3QgdXNlcyBiaW5vbWlhbCBsb2dpdCByZWdyZXNzaW9uIG1vZGVscyB0byBhbmFseXplIHRoZSBwcm9iYWJpbGl0eSBvZiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzIGFmZmVjdGluZyBhIGJpbmFyeSBvdXRjb21lOiBkYW1hZ2VkIG9yIG5vdCBkYW1hZ2VkLg0KDQpUaGUgcHJvamVjdHMgd29ya2Zsb3cgaXMgYXMgZm9sbG93czoNCg0KMS4gQ3JlYXRlIEZpc2huZXQNCg0KMi4gRW5naW5lZXIgRmVhdHVyZXMgaW4gQXJjR0lTIChmZWF0dXJlIC0+IHJhc3RlciAtPiB0YWJsZSkNCg0KMy4gSW1wb3J0IGFuZCBqb2luIGZlYXR1cmVzIGluIFINCg0KMy4gUHJvY2VzcyBhbmQgZXhwbG9yZSBkYXRhDQoNCjQuIFNlbGVjdCBWYXJpYWJsZXMNCg0KNS4gVGVzdCB2YXJpYWJsZXMgZm9yIGNvcnJlbGF0aW9uDQoNCjYuIEJ1aWxkIGFuZCBJdGVyYXRlIEJpbm9taWFsIExvZ2l0IE1vZGVscw0KDQo3LiBUZXN0IG1vZGVsIHByZWRpY3Rpb24gYWNjdXJhY3kNCg0KOC4gSW50ZXJwcmV0IFJlc3VsdHMNCg0KPGJyPg0KPGJyPg0KDQojIERhdGENCg0KIyMgRGF0YSBTb3VyY2VzDQoNClRoaXMgcHJvamVjdCBkcmF3cyBmcm9tIHRoZSBmb2xsb3dpbmcgZGF0YSBzb3VyY2VzOiAgDQoNCiogQSAiW0RhbWFnZWQgUHJvcGVydGllc10oaHR0cHM6Ly9vcGVuZGF0YS5taW5uZWFwb2xpc21uLmdvdi9kYXRhc2V0cy9jaXR5b2ZsYWtlczo6ZGFtYWdlZC1wcm9wZXJ0aWVzLXB1YmxpYy9hYm91dCkiIGZlYXR1cmUgbGF5ZXIgZnJvbSB0aGUgTWlubmVhcG9saXMgb3BlbiBkYXRhIHBvcnRhbCANCg0KKiBBIFtQb2xpY2UgU3RhdGlvbnNdKGh0dHBzOi8vb3BlbmRhdGEubWlubmVhcG9saXNtbi5nb3YvZGF0YXNldHMvcG9saWNlLXN0YXRpb25zL2V4cGxvcmUpIGZlYXR1cmUgbGF5ZXIgZnJvbSB0aGUgTWlubmVhcG9saXMgb3BlbiBkYXRhIHBvcnRhbCAgDQoNCiogQSBEYXRhc2V0IG9mIFthbGwgTWlubmVhcG9saXMgcGFyY2Vsc10oaHR0cHM6Ly9naXMtaGVubmVwaW4uaHViLmFyY2dpcy5jb20vZGF0YXNldHMvY291bnR5LXBhcmNlbHMvZXhwbG9yZSkgd2l0aCB1c2UsIHRheGFibGUgdmFsdWUsIGFuZCBwcmltYXJ5IHRheHBheWVyIGFkZHJlc3MgZnJvbSB0aGUgSGVubmVwaW4gQ291bnR5IG9wZW4gZGF0YSBwb3J0YWwgICANCg0KKiBNZWRpYW4gSG91c2Vob2xkIGluY29tZSBhbmQgcmFjZSBkYXRhIGZyb20gdGhlIFUuUy4gQ2Vuc3VzIEJ1cmVhdSdzIDIwMjAgNS1ZZWFyIEFDUyANCg0KPGJyPg0KDQojIyBWYXJpYWJsZXMNCg0KVGhlIHVuaXQgb2YgYW5hbHlzaXMgaXMgYSAxLzggbWlsZSBkaWFtZXRlciBmaXNobmV0IGdyaWQgY2VsbC4NCg0KVGhlIGRlcGVuZGVudCB2YXJpYWJsZSBpcyBkYW1hZ2Ugc3RhdHVzIChkYW1hZ2VkIHZzLiBub3QpLg0KDQpUaGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzIG9mIGludGVyZXN0IGFyZTogIA0KKiBQcm9wZXJ0eSB0eXBlIChjb21tZXJjaWFsIG9yIG5vdCkgIA0KKiBEYW1hZ2VkIHByb3BlcnRpZXMgIA0KKiBEaXN0YW5jZSBmcm9tIFByb3Rlc3QgU2l0ZSAgDQoqIERpc3RhbmNlIGZyb20gUG9saWNlIFN0YXRpb24gIA0KKiBBYnNlbnRlZSBvd25lcnNoaXAgIA0KKiBUYXhhYmxlIHByb3BlcnR5IHZhbHVlICANCiogJSBXaGl0ZSAgDQoqIE1lZGlhbiBISCBJbmNvbWUgIA0KDQo8YnI+DQoNCg0KIyMgRGF0YSBQcm9jZXNzaW5nDQoNCmBgYHtyIGxvYWQgZGF0YSBhbmQgcGxvdCBpdCwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9DQojZGFtYWdlZCBwYXJjZWxzDQpwYXJjZWxzX2RtZyA8LSByZWFkX3NmKCJQcm9jZXNzZWQvUGFyY2Vsc1dpdGhEbWdfc2hwL1BhcmNlbHNfd0RtZy5zaHAiKQ0KDQojYWxsIHBhcmNlbHMgaW4gTWlubmVhcG9saXMNCiNwYXJjZWxzX2FsbCA8LSByZWFkX3NmKCJQcm9jZXNzZWQvTWlubmVhcG9saXNfUGFyY2Vsc18yMDIxL01pbm5lYXBvbGlzX1BhcmNlbHNfMjAyMS5zaHAiKQ0KDQojbXNwIGJvdW5kYXJ5DQptc3BfYm91bmRhcnkgPC0gcmVhZF9zZigiUmF3L0NpdHlfQm91bmRhcnktc2hwLzE2Y2RiYmZhLWFkMTAtNDkzYy1hZmFmLTUyYjYxZjJlNzZlNDIwMjAzMjktMS0xODBoOWFwLndoYm8uc2hwIikNCg0KbXNwX2JvdW5kYXJ5IDwtIG1zcF9ib3VuZGFyeSAlPiUgDQogIHN0X3RyYW5zZm9ybShjcnMgPSA2NTA1KQ0KYGBgDQoNClRoZSBjaXR5IG9mIE1pbm5lYXBvbGlzIGNvbGxlY3RlZCBhIGRhdGFzZXQgb2YgcHJvcGVydGllcyB0aGF0IHdlcmUgZGFtYWdlZCBkdXJpbmcgdGhlIGZvdXItZGF5IHBlcmlvZCBvZiBncmVhdGVzdCB1bnJlc3QgYmV0d2VlbiBNYXkgMjV0aCBhbmQgTWF5IDI5dGgsIDIwMjAuIFRoZSBkYXRhc2V0IGxpc3RzIDExODIgZGFtYWdlZCBwcm9wZXJ0aWVzLg0KDQpXaGlsZSB0aGlzIGRhdGFzZXQgaXMgcmVsYXRpdmVseSBzbWFsbCwgdG8gcnVuIGJpbm9taWFsIGxvZ2l0IHJlZ3Jlc3Npb25zLCB3ZSBuZWVkIHRvIGNvbXBhcmUgZGFtYWdlZCBwcm9wZXJ0aWVzIHRvIGFsbCBwcm9wZXJ0aWVzIGluIHRoZSBjaXR5LCBvZiB3aGljaCB0aGVyZSBhcmUgb3ZlciAxMjksMDAwIQ0KDQojIyBDcmVhdGUgRmlzaG5ldA0KVG8gYWdncmVnYXRlIGRhdGEgYW5kIHNwZWVkIHByb2Nlc3NpbmcgdGltZSwgSSBjcmVhdGVkIGEgZ3JpZCBvZiAxLzggbWlsZSBmaXNobmV0IGNlbGxzIHRoYXQgY292ZXJzIE1pbm5lYXBvbGlzIChzaG93biBiZWxvdykuDQoNCmBgYHtyIGNyZWF0ZSBmaXNobmV0LCBldmFsPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgZWNobz1GQUxTRX0NCiNTa2lwIHRoaXMgd2hlbiBydW5uaW5nDQptc3BfZmlzaG5ldCA8LSBzdF9tYWtlX2dyaWQobXNwX2JvdW5kYXJ5LA0KICAgICAgICAgICAgICAgICAgICAgICAgY2VsbHNpemUgPSA2NjAsDQogICAgICAgICAgICAgICAgICAgICAgICBzcXVhcmUgPSBGQUxTRSkgJT4lICANCiAuW21zcF9ib3VuZGFyeV0gJT4lIA0KICBzdF9zZigpICU+JSANCiAgbXV0YXRlKHVuaXF1ZUlEID0gcm93bmFtZXMoLikpDQoNCnN0X3dyaXRlKG1zcF9maXNobmV0LCAiUHJvY2Vzc2VkL21zcF9maXNobmV0L21zcF9maXNobmV0LnNocCIsIGdlb21ldHJ5ID0gVFJVRSwgYXBwZW5kID0gRkFMU0UpDQpgYGANCg0KDQpgYGB7ciBwbG90IG1zcCBmaXNobmV0fQ0KbXNwX2Zpc2huZXQgPC0gc3RfcmVhZCgiUHJvY2Vzc2VkL21zcF9maXNobmV0L21zcF9maXNobmV0LnNocCIpDQoNCm1zcF9maXNobmV0IDwtIG1zcF9maXNobmV0ICU+JQ0KICBzdF90cmFuc2Zvcm0oY3JzID0gNjUwNSkNCg0KbWFwXzEgPC0gDQpnZ3Bsb3QoKSsNCiAgZ2VvbV9zZihkYXRhID0gbXNwX2Zpc2huZXQsDQogICAgICAgICAgZmlsbCA9ICJsaWdodGdyZXkiKSArDQogIGdlb21fc2YoZGF0YSA9IG1zcF9ib3VuZGFyeSwgDQogICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBmaWxsID0gInRyYW5zcGFyZW50IikgKw0KICBtYXBUaGVtZQ0KDQptYXBfMQ0KYGBgDQo8YnI+DQoNCiMjIEZlYXR1cmUgRW5naW5lZXJpbmc6IEZyb20gQXJjIHRvIFINCg0KQWZ0ZXIgY3JlYXRpbmcgdGhlIGZpc2huZXQgZm9yIE1pbm5lYXBvbGlzLCBJIGV4cG9ydGVkIGl0IGFzIGEgc2hhcGVmaWxlIGZvciBwcm9jZXNzaW5nIGluIEFyY0dJUy4gVGhlcmUsIEkgdHVybmVkIGVhY2ggZmVhdHVyZSBpbnRvIGEgcmFzdGVyIGxheWVyIGFuZCB0aGVuIHVzZWQgdGhlIFpvbmFsIFN0YXRpc3RpY3MgYXMgVGFibGUgdG9vbCB0byBhZ2dyZWdhdGUgdGhlIHZhbHVlcyBvZiBlYWNoIHJhc3RlciBieSBmaXNobmV0IGNlbGwuIEkgdGhlbiBleHBvcnRlZCB0aGVzZSB0YWJsZXMgb2Ygem9uYWwgc3RhdGlzdGljcyBhbmQgYnJvdWdodCB0aGVtIGJhY2sgaW50byBSIHdoZXJlIEkgam9pbmVkIGVhY2ggdGFibGUgd2l0aCB0aGUgZmlzaG5ldCBmaWxlLg0KDQpgYGB7ciBsb2FkIGluIGZlYXR1cmVzIGZyb20gYXJjfQ0KI0xvYWQgaW4gZmVhdHVyZXMgdGhhdCB3ZXJlIGVuZ2luZWVyZWQgaW4gYXJjDQpkYW1hZ2VkIDwtIHJlYWRfY3N2KCJQcm9jZXNzZWQvWm9uYWxTdGF0c1RhYmxlcy9ab25hbFN0YXRzX2RtZ2RwcmNscy5jc3YiKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QodW5pcXVlSUQsIFNVTSkgJT4lIA0KICBtdXRhdGUoZGFtYWdlZCA9IGlmZWxzZShTVU0gPiAzLCAxLCAwKSkgJT4lIA0KICByZW5hbWUoZG1nX1NVTSA9IFNVTSkNCg0KY29tbWVyY2lhbF9jb3VudCA8LSByZWFkX2NzdigiUHJvY2Vzc2VkL1pvbmFsU3RhdHNUYWJsZXMvWm9uYWxTdGF0c19jb21tZXJjaWFsMi5jc3YiKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QodW5pcXVlSUQsIFNVTSkgJT4lIA0KICByZW5hbWUoY21tcmNsX3N1bSA9IFNVTSkNCg0KY29tbWVyY2lhbF9iaW5hcnkgPC0gcmVhZF9jc3YoIlByb2Nlc3NlZC9ab25hbFN0YXRzVGFibGVzL1pvbmFsU3RhdHNfQ21yY2xDcmRyLmNzdiIpICU+JSANCiAgZHBseXI6OnNlbGVjdCh1bmlxdWVJRCwgQ21tcmNsQ3JkcikgJT4lIA0KICByZW5hbWUoY21tcmNsX2JpbmFyeSA9IENtbXJjbENyZHIpDQoNCmRpc3RfcHJvdGVzdCA8LSByZWFkX2NzdigiUHJvY2Vzc2VkL1pvbmFsU3RhdHNUYWJsZXMvWm9uYWxTdGF0c19kaXN0X3Byb3Rlc3QuY3N2IikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHVuaXF1ZUlELCBNSU4pICU+JSANCiAgcmVuYW1lKERJU1RfUFJUU1QgPSBNSU4pDQoNCmRpc3RfcG9saWNlIDwtIHJlYWRfY3N2KCJQcm9jZXNzZWQvWm9uYWxTdGF0c1RhYmxlcy9ab25hbFN0YXRzX2Rpc3RfcG9saWNlLmNzdiIpICU+JSANCiAgZHBseXI6OnNlbGVjdCh1bmlxdWVJRCwgTUlOKSAlPiUgDQogIHJlbmFtZShESVNUX1BPTEMgPSBNSU4pDQoNClRBWFZBTFVFIDwtIHJlYWRfY3N2KCJQcm9jZXNzZWQvWm9uYWxTdGF0c1RhYmxlcy9ab25hbFN0YXRzX3RheHZhbHVlLmNzdiIpICU+JSANCiAgZHBseXI6OnNlbGVjdCh1bmlxdWVJRCwgTUVBTikgJT4lIA0KICByZW5hbWUodmFsdWVfbWVhbiA9IE1FQU4pDQoNCmFic2VudGVlIDwtIHJlYWRfY3N2KCJQcm9jZXNzZWQvWm9uYWxTdGF0c1RhYmxlcy9ab25hbFN0YXRzX0Fic2VudGVlT3duZXJzLmNzdiIpICU+JSANCiAgZHBseXI6OnNlbGVjdCh1bmlxdWVJRCwgU1VNKSAlPiUgDQogIHJlbmFtZShhYnNudGVlX3N1bSA9IFNVTSkNCg0KaGhJbmNvbWUgPC0gcmVhZF9jc3YoIlByb2Nlc3NlZC9ab25hbFN0YXRzVGFibGVzL1pvbmFsU3RhdHNfaGhpbmNvbWVfYWNzXzIwMjAuY3N2IikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHVuaXF1ZUlELCBNRURJQU4pICU+JSANCiAgcmVuYW1lKGhoSW5jb21lX21lZCA9IE1FRElBTikNCiAgDQpwY3RXaGl0ZSA8LSByZWFkX2NzdigiUHJvY2Vzc2VkL1pvbmFsU3RhdHNUYWJsZXMvWm9uYWxTdGF0c19wY3RXaGl0ZV9hY3NfMjAyMC5jc3YiKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QodW5pcXVlSUQsIE1FRElBTikgJT4lIA0KICByZW5hbWUocGN0V2hpdGVfbWVkID0gTUVESUFOKQ0KDQojSm9pbiBmZWF0dXJlcyB3aXRoIGZpc2huZXQgYW5kIHJlbW92ZSBOQXMNCmRhdCA8LSBtc3BfZmlzaG5ldCAlPiUNCiAgbXV0YXRlKHVuaXF1ZUlEID0gYXMuaW50ZWdlcih1bmlxdWVJRCkpICU+JSANCiAgbGVmdF9qb2luKGNvbW1lcmNpYWxfY291bnQsIGJ5ID0gInVuaXF1ZUlEIikgJT4lIA0KICBsZWZ0X2pvaW4oY29tbWVyY2lhbF9iaW5hcnksIGJ5ID0gInVuaXF1ZUlEIikgJT4lIA0KICBsZWZ0X2pvaW4oZGFtYWdlZCwgYnkgPSAidW5pcXVlSUQiKSAlPiUNCiAgbGVmdF9qb2luKGRpc3RfcHJvdGVzdCwgYnkgPSAidW5pcXVlSUQiKSAlPiUgDQogIGxlZnRfam9pbihkaXN0X3BvbGljZSwgYnkgPSAidW5pcXVlSUQiKSAlPiUgDQogIGxlZnRfam9pbihUQVhWQUxVRSwgYnkgPSAidW5pcXVlSUQiKSAlPiUgDQogIGxlZnRfam9pbihhYnNlbnRlZSwgYnkgPSAidW5pcXVlSUQiKSAlPiUgDQogIGxlZnRfam9pbihoaEluY29tZSwgYnkgPSAidW5pcXVlSUQiKSAlPiUgDQogIGxlZnRfam9pbihwY3RXaGl0ZSwgYnkgPSAidW5pcXVlSUQiKSAlPiUgDQogIG5hLm9taXQoKQ0KDQojbG9nIGFkanVzdA0KZGF0JHZhbHVlX2xvZyA8LSBsb2coZGF0JHZhbHVlX21lYW4pDQojcmVwbGFjZSBpbmZpbml0ZSB2YWx1ZXMgd2l0aCB6ZXJvcw0KZGF0JHZhbHVlX2xvZ1tzYXBwbHkoZGF0JHZhbHVlX2xvZywgaXMuaW5maW5pdGUpXSA8LSAwDQoNCiNkaXNwbGF5IGFzIGludGVyYWN0aXZlIHRhYmxlDQpyZWFjdGFibGUoZGF0LCBkZWZhdWx0UGFnZVNpemUgPSA1KQ0KYGBgDQoNCiMgRXhwbG9yYXRvcnkgQW5hbHlzaXMNCg0KIyMgTWFwcw0KDQpCZWxvdyBhcmUgbWFwcyBvZiBlYWNoIG9mIHRoZSBmZWF0dXJlczoNCg0KYGBge3IgbWFwcyAxLCBmaWcuaGVpZ2h0PTh9DQojQ3JlYXRlIGxheWVyIHdpdGgganVzdCBkYW1hZ2VkIHByb3BlcnR5IGNlbGxzDQpmaXNobmV0X2RtZyA8LSBkYXQgJT4lIA0KICBmaWx0ZXIoZGFtYWdlZCA9PSAxKQ0KDQojU2V0IG1hcCBwcm9qZWN0aW9uDQpkYXQgPC0gZGF0ICU+JQ0KICBzdF90cmFuc2Zvcm0oY3JzID0gNjUwNSkNCg0KbWFwXzIgPC0NCmdncGxvdCgpICsNCiAgZ2VvbV9zZihkYXRhID0gZGF0LCBhZXMoZmlsbD1hcy5mYWN0b3IoZGFtYWdlZCkpLCBhbHBoYSA9IDAuOCwgY29sb3IgPSAidHJhbnNwYXJlbnQiKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpcyhsYWJlbHMgPSBjKCdOb3QgRGFtYWdlZCcsICdEYW1hZ2VkJyksDQogICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAuNzUsDQogICAgICAgICAgICAgICAgICAgICAgYmVnaW4gPSAwLjA1LA0KICAgICAgICAgICAgICAgICAgICAgIGVuZCA9IDAuOCwNCiAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAxLA0KICAgICAgICAgICAgICAgICAgICAgIGRpc2NyZXRlID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICBvcHRpb24gPSAiQiIpICsNCiAgZ2VvbV9zZihkYXRhPW1zcF9ib3VuZGFyeSwNCiAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwNCiAgICAgICAgICBjb2xvciA9ICIjNDc0NzQ3IiwNCiAgICAgICAgICBzaXplID0gLjUpICsNCiAgZ2VvbV9zZihkYXRhPWZpc2huZXRfZG1nLA0KICAgICAgICAgIGZpbGwgPSAidHJhbnNwYXJlbnQiLA0KICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgICBzaXplID0gLjI1KSArDQogIGxhYnModGl0bGUgPSJEYW1hZ2VkIFByb3BlcnRpZXMiLA0KICAgICAgIGZpbGwgPSAiU3RhdHVzIiwNCiAgICAgICBjYXB0aW9uID0gIlNvdXJjZTogb3BlbmRhdGEubWlubmVhcG9saXNtbi5nb3YiKSArDQogIG1hcFRoZW1lDQoNCm1hcF8yDQpgYGANCg0KRm9yIGRhbWFnZWQgcHJvcGVydGllcywgSSBzdW1tZWQgdGhlIGFyZWEgb2YgZGFtYWdlZCBwcm9wZXJ0eSBieSBjZWxsLCBhbmQgdGhlbiBzYWlkIGFueSBjZWxsIGNvbnRhaW5pbmcgbW9yZSB0aGFuIDMgcmFzdGVyIHBpeGVscyBvZiBkYW1hZ2VkIHByb3BlcnRpZXMgaXMgZGFtYWdlZCwgYW5kIGV2ZXJ5IG90aGVyIGNlbGwgaXNuJ3QuIFRoZXJlZm9yZSwgYWZ0ZXIgdGhpcyBzdGVwLCBkYW1hZ2VkIGZpc2huZXQgY2VsbHMgaGF2ZSBhIHZhbHVlIG9mIDEgYW5kIHVuZGFtYWdlZCBjZWxscyBoYXZlIGEgdmFsdWUgb2YgemVyby4NCg0KYGBge3IgbWFwcyBjb21tZXJjaWFsLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KI1NldCBtYXAgcHJvamVjdGlvbg0KZGF0IDwtIGRhdCAlPiUNCiAgc3RfdHJhbnNmb3JtKGNycyA9IDY1MDUpDQoNCm1hcF82IDwtDQpncmlkLmFycmFuZ2UobmNvbCA9IDIsDQpnZ3Bsb3QoKSArDQogIGdlb21fc2YoZGF0YSA9IGRhdCwgYWVzKGZpbGw9YXMuZmFjdG9yKGNtbXJjbF9iaW5hcnkpKSwgYWxwaGEgPSAwLjgsIGNvbG9yID0gInRyYW5zcGFyZW50IikgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXMobGFiZWxzID0gYygnTm8nLCAnWWVzJyksDQogICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAuNzUsDQogICAgICAgICAgICAgICAgICAgICAgYmVnaW4gPSAwLjA1LA0KICAgICAgICAgICAgICAgICAgICAgIGVuZCA9IDAuOCwNCiAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAxLA0KICAgICAgICAgICAgICAgICAgICAgIGRpc2NyZXRlID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICBvcHRpb24gPSAiQiIpICsNCiAgZ2VvbV9zZihkYXRhPW1zcF9ib3VuZGFyeSwNCiAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwNCiAgICAgICAgICBjb2xvciA9ICIjNDc0NzQ3IiwNCiAgICAgICAgICBsaW5ld2lkdGggPSAuNSkgKw0KICBnZW9tX3NmKGRhdGE9ZmlzaG5ldF9kbWcsDQogICAgICAgICAgZmlsbCA9ICJ0cmFuc3BhcmVudCIsDQogICAgICAgICAgY29sb3IgPSAid2hpdGUiLA0KICAgICAgICAgIHNpemUgPSAuMjUpICsNCiAgbGFicyh0aXRsZSA9Ik9uIENvbW1lcmNpYWxcbkNvcnJpZG9yIiwNCiAgICAgICBmaWxsID0gIlN0YXR1cyIsDQogICAgICAgY2FwdGlvbiA9ICJTb3VyY2U6IG9wZW5kYXRhLm1pbm5lYXBvbGlzbW4uZ292IikgKw0KICBtYXBUaGVtZSwNCg0KZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBkYXQsIGFlcyhmaWxsPWNtbXJjbF9zdW0pLCBhbHBoYSA9IDAuOCwgY29sb3IgPSAidHJhbnNwYXJlbnQiKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpcygNCiAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gLjc1LA0KICAgICAgICAgICAgICAgICAgICAgYmVnaW4gPSAwLA0KICAgICAgICAgICAgICAgICAgICAgZW5kID0gMC45LA0KICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gMSwNCiAgICAgICAgICAgICAgICAgICAgIGRpc2NyZXRlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICBvcHRpb24gPSAiQiIpICsNCiAgZ2VvbV9zZihkYXRhPW1zcF9ib3VuZGFyeSwNCiAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwNCiAgICAgICAgICBjb2xvciA9ICIjNDc0NzQ3IiwNCiAgICAgICAgICBsaW5ld2lkdGggPSAuNSkgKw0KICBnZW9tX3NmKGRhdGE9ZmlzaG5ldF9kbWcsDQogICAgICAgICAgZmlsbCA9ICJ0cmFuc3BhcmVudCIsDQogICAgICAgICAgY29sb3IgPSAid2hpdGUiLA0KICAgICAgICAgIHNpemUgPSAuMjUpICsNCiAgbGFicyh0aXRsZSA9IkNvbW1lcmNpYWwgUHJvcGVydGllcyIsDQogICAgICAgZmlsbCA9ICJDb3VudCIsDQogICAgICAgY2FwdGlvbiA9ICJTb3VyY2U6IGdpcy1oZW5uZXBpbi5odWIuYXJjZ2lzLmNvbSIpICsNCiAgbWFwVGhlbWUNCikNCmBgYA0KDQpGb3IgY2VsbHMgb24gYSBjb21tZXJjaWFsIGNvcnJpZG9yLCBJIHVzZWQgQXJjR0lTIHRvIHNldCBhbnkgY2VsbCB0aGF0IGludGVyc2VjdGVkIHdpdGggYSBjb21tZXJjaWFsIGNvcnJpZG9yIHRvIDEuIFRvIGNyZWF0ZSB0aGUgY29tbWVyY2lhbCBwcm9wZXJ0aWVzIHZhcmlhYmxlLCBJIHNpbXBseSBzdW1tZWQgdGhlIG51bWJlciBvZiBjb21tZXJjaWFsIHJhc3RlciBwaXhlbHMgYnkgZmlzaG5ldCBjZWxsLiBBcyBhIHJlc3VsdCwgdGhpcyB2YXJpYWJsZSBhcHByb3hpbWF0ZXMgdGhlIGNvbW1lcmNpYWwgYXJlYSBvZiBlYWNoIGNlbGwuDQoNCmBgYHtyIG1hcHMgMiwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0NCmRhdCA8LSBkYXQgJT4lDQogIHN0X3RyYW5zZm9ybShjcnMgPSA2NTA1KQ0KDQptYXBfMyA8LQ0KZ3JpZC5hcnJhbmdlKG5jb2wgPSAyLA0KZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBkYXQsIGFlcyhmaWxsPURJU1RfUFJUU1QpLCBhbHBoYSA9IDAuOCwgY29sb3IgPSAidHJhbnNwYXJlbnQiKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpcygNCiAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IC43NSwNCiAgICAgICAgICAgICAgICAgICAgICBiZWdpbiA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgZW5kID0gMC45LA0KICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9IC0xLA0KICAgICAgICAgICAgICAgICAgICAgIGRpc2NyZXRlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gIkIiKSArDQogIGdlb21fc2YoZGF0YT1tc3BfYm91bmRhcnksDQogICAgICAgICAgZmlsbCA9ICJ0cmFuc3BhcmVudCIsDQogICAgICAgICAgY29sb3IgPSAiIzQ3NDc0NyIsDQogICAgICAgICAgc2l6ZSA9IC41KSArDQogIGdlb21fc2YoZGF0YT1maXNobmV0X2RtZywNCiAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwNCiAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgc2l6ZSA9IC4yNSkgKw0KICBsYWJzKHRpdGxlID0iRGlzdGFuY2UgZnJvbSBQcm90ZXN0IFNpdGVzIiwNCiAgICAgICBmaWxsID0gIkRpc3RhbmNlIChmdCkiLA0KICAgICAgIGNhcHRpb24gPSAiU291cmNlOiBNYXBwaW5nIFByb3Rlc3QgMjAyMCIpICsNCiAgbWFwVGhlbWUsDQoNCmdncGxvdCgpICsNCiAgZ2VvbV9zZihkYXRhID0gZGF0LCBhZXMoZmlsbD1ESVNUX1BPTEMpLCBhbHBoYSA9IDAuOCwgY29sb3IgPSAidHJhbnNwYXJlbnQiKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpcygNCiAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IC43NSwNCiAgICAgICAgICAgICAgICAgICAgICBiZWdpbiA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgZW5kID0gMC45LA0KICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9IC0xLA0KICAgICAgICAgICAgICAgICAgICAgIGRpc2NyZXRlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gIkIiKSArDQogIGdlb21fc2YoZGF0YT1tc3BfYm91bmRhcnksDQogICAgICAgICAgZmlsbCA9ICJ0cmFuc3BhcmVudCIsDQogICAgICAgICAgY29sb3IgPSAiIzQ3NDc0NyIsDQogICAgICAgICAgc2l6ZSA9IC41KSArDQogIGdlb21fc2YoZGF0YT1maXNobmV0X2RtZywNCiAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwNCiAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgc2l6ZSA9IC4yNSkgKw0KICBsYWJzKHRpdGxlID0iRGlzdGFuY2UgZnJvbSBQb2xpY2UgU3RhdGlvbnMiLA0KICAgICAgIGZpbGwgPSAiRGlzdGFuY2UgKGZ0KSIsDQogICAgICAgY2FwdGlvbiA9ICJTb3VyY2U6IG9wZW5kYXRhLm1pbm5lYXBvbGlzbW4uZ292IikgKw0KICBtYXBUaGVtZQ0KKQ0KICAgICAgICAgICAgIA0KYGBgDQoNClRvIGNyZWF0ZSB0aGUgZGlzdGFuY2UgZnJvbSBwcm90ZXN0IHNpdGVzIGFuZCBwb2xpY2Ugc3RhdGlvbnMgdmFyaWFibGVzLCBJIGFzc2lnbmVkIGVhY2ggY2VsbCB0aGUgbWluaW11bSBkaXN0YW5jZSBpdCBjb250YWluZWQuIFRoaXMgd2FzIHRvIGF2b2lkIHVuZGVyIHNhbXBsaW5nIHRoaXMga2V5IG1ldHJpYy4NCg0KDQpgYGB7ciBtYXBzIDMsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwfQ0KZGF0IDwtIGRhdCAlPiUNCiAgc3RfdHJhbnNmb3JtKGNycyA9IDY1MDUpDQoNCm1hcF80IDwtIA0KZ3JpZC5hcnJhbmdlKG5jb2wgPSAyLA0KICAgICAgICAgICAgIA0KZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBkYXQsIGFlcyhmaWxsPXZhbHVlX2xvZyksIGFscGhhID0gMC44LCBjb2xvciA9ICJ0cmFuc3BhcmVudCIpICsNCiAgc2NhbGVfZmlsbF92aXJpZGlzKA0KICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gLjc1LA0KICAgICAgICAgICAgICAgICAgICAgIGJlZ2luID0gMC4wNSwNCiAgICAgICAgICAgICAgICAgICAgICBlbmQgPSAwLjg1LA0KICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgZGlzY3JldGUgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBvcHRpb24gPSAiQiIpICsNCiAgZ2VvbV9zZihkYXRhPW1zcF9ib3VuZGFyeSwNCiAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwNCiAgICAgICAgICBjb2xvciA9ICIjNDc0NzQ3IiwNCiAgICAgICAgICBzaXplID0gLjUpICsNCiAgZ2VvbV9zZihkYXRhPWZpc2huZXRfZG1nLA0KICAgICAgICAgIGZpbGwgPSAidHJhbnNwYXJlbnQiLA0KICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgICBzaXplID0gLjI1KSArDQogIGxhYnModGl0bGUgPSJNZWFuIFRheGFibGUgVmFsdWUgKGxvZykiLA0KICAgICAgIGZpbGwgPSAiVmFsdWUgKCQpIiwNCiAgICAgICBjYXB0aW9uID0gIlNvdXJjZTogZ2lzLWhlbm5lcGluLmh1Yi5hcmNnaXMuY29tIikgKw0KICBtYXBUaGVtZSwNCg0KZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBkYXQsIGFlcyhmaWxsPWFic250ZWVfc3VtKSwgYWxwaGEgPSAwLjgsIGNvbG9yID0gInRyYW5zcGFyZW50IikgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXMoDQogICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAuNzUsDQogICAgICAgICAgICAgICAgICAgICAgYmVnaW4gPSAwLA0KICAgICAgICAgICAgICAgICAgICAgIGVuZCA9IDAuOSwNCiAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAxLA0KICAgICAgICAgICAgICAgICAgICAgIGRpc2NyZXRlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gIkIiKSArDQogIGdlb21fc2YoZGF0YT1tc3BfYm91bmRhcnksDQogICAgICAgICAgZmlsbCA9ICJ0cmFuc3BhcmVudCIsDQogICAgICAgICAgY29sb3IgPSAiIzQ3NDc0NyIsDQogICAgICAgICAgc2l6ZSA9IC41KSArDQogIGdlb21fc2YoZGF0YT1maXNobmV0X2RtZywNCiAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwNCiAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgc2l6ZSA9IC4yNSkgKw0KICBsYWJzKHRpdGxlID0iTm9uIE1TUCBSZXNpZGVudCBPd25lZCBQcm9wZXJ0aWVzIiwNCiAgICAgICBmaWxsID0gIkNvdW50IiwNCiAgICAgICBjYXB0aW9uID0gIlNvdXJjZTogZ2lzLWhlbm5lcGluLmh1Yi5hcmNnaXMuY29tIikgKw0KICBtYXBUaGVtZQ0KKQ0KYGBgDQoNClRvIGNyZWF0ZSB0aGUgcHJvcGVydHkgdmFsdWUgdmFyaWFibGUsIEkgdG9vayB0aGUgbWVhbiB2YWx1ZSBvZiB0aGUgcmFzdGVyIHBpeGVscyBpbiBlYWNoIGNlbGwgKGhlcmUgdGhleSdyZSBzaG93biBsb2ctdHJhbnNmb3JtZWQgZm9yIGdyZWF0ZXIgY2xhcml0eSkuDQoNCkNhbGN1bGF0aW5nIGFic2VudGVlIG93bmVyc2hpcCB3YXMgYSBsaXR0bGUgbW9yZSBpbnZvbHZlZC4gSSB3YW50ZWQgdG8gaW5jbHVkZSB0aGlzIHZhcmlhYmxlIHRvIHRlc3QgdGhlIG5hcnJhdGl2ZSB0aGF0IHByb3BlcnRpZXMgd2l0aCBhYnNlbnRlZSBvd25lcnMgcmVjaWV2ZWQgbW9yZSBkYW1hZ2UgdGhhbiBvdGhlcnMuIFVubGlrZSB0aGUgb3RoZXIgdmFyaWFibGVzIHRoaXMgcHJvZWN0IGV4YW1pbmVzLCBhYnNlbnRlZSBvd25lcnNoaXAgd2FzIG5vdCBhbiBleGlzdGluZyBmaWVsZCBpbiB0aGUgcGFyY2VscyBkYXRhc2V0LiBJbmNsdWRpbmcgdGhpcyB2YXJpYWJsZSBpbiB0aGUgYW5hbHlzaXMgcmVxdWlyZWQgY29taW5nIHVwIHdpdGggYSBtZXRob2RvbG9neSBmb3IgY2xhc3NpZnlpbmcgcHJvcGVydGllcyB3aXRoIG93bmVycyB3aG8gZGlkIG5vdCBsaXZlIG5lYXIgdGhlaXIgcHJvcGVydGllcy4gVGhpcyBwcm9qZWN0IGRlZmluZXMgcGFyY2VscyB3aXRoIGFic2VudGVlIG93bmVycyBhcyBhbnkgcGFyY2VsIHdoZXJlIHRoZSBwcmltYXJ5IHRheHBheWVyJ3MgYWRkcmVzcyBpcyBub3QgaW4gTWlubmVhcG9saXMuIFRoZSBjb2RlIGNodW5rIGJlbG93IGNvbnRhaW5zIG15IG1ldGhvZC4NCg0KYGBge3IgYWJzZW50ZWUgb3duZXJzaGlwLCBldmFsPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30NCiNTa2lwIHRoaXMNCnBhcmNlbHNfb3duZXIgPC0gcGFyY2Vsc19hbGwgJT4lIA0KICBkcGx5cjo6c2VsZWN0KE9CSkVDVElELCBQSUQsIFpJUF9DRCwgVEFYUEFZRVJfMSwgVEFYUEFZRVJfMiwgVEFYUEFZRVJfMykNCg0KcGFyY2Vsc19vd25lciRvd25lcl9tc3AgPC0gDQogIGlmZWxzZShncmVwbCgiTUlOTkVBUE9MSVMiLCBwYXJjZWxzX293bmVyJFRBWFBBWUVSXzIpIHwNCiAgICAgICAgIGdyZXBsKCJNSU5ORUFQT0xJUyIsIHBhcmNlbHNfb3duZXIkVEFYUEFZRVJfMykgfA0KICAgICAgICAgZ3JlcGwoIk1QTFMiLCBwYXJjZWxzX293bmVyJFRBWFBBWUVSXzIpIHwNCiAgICAgICAgIGdyZXBsKCJNUExTIiwgcGFyY2Vsc19vd25lciRUQVhQQVlFUl8zKSANCiAgICAgICAgICwgMSwwKQ0KDQpwYXJjZWxzX293bmVyIDwtIHBhcmNlbHNfb3duZXIgJT4lIA0KICBtdXRhdGUob3duZXJfbW4gPSBjYXNlX3doZW4oDQogICAgKGdyZXBsKCJNTiIsIFRBWFBBWUVSXzIpIHwgZ3JlcGwoIk1OIiwgVEFYUEFZRVJfMykpICYgb3duZXJfbXNwICE9IDEgfiAxLA0KICAgIFRSVUUgfiAwDQogICkpDQoNCnBhcmNlbHNfb3duZXIgPC0gcGFyY2Vsc19vd25lciAlPiUgDQogIG11dGF0ZShvd25lcl9ub25fbW4gPSBpZmVsc2UoKG93bmVyX21zcCA9PSAxIHwgb3duZXJfbW4gPT0xKSwgMCwgMSkpDQoNCnBhcmNlbHNfb3duZXIgPC0gcGFyY2Vsc19vd25lciAlPiUgDQogIG11dGF0ZShvd25lcl9ub25fbXNwID0gY2FzZV93aGVuKA0KICAgIG93bmVyX25vbl9tbiA9PSAxIHwgb3duZXJfbW4gPT0gMSAmIG93bmVyX21zcCA9PSAwIH4gMSwNCiAgICBUUlVFIH4gMA0KICApKQ0KDQp3cml0ZV9zZihwYXJjZWxzX293bmVyLCAiUHJvY2Vzc2VkL3BhcmNlbHNfb3duZXJzaGlwL3BhcmNlbHNfYnlvd25lci5zaHAiKQ0KYGBgDQoNCmBgYHtyIG1hcHMgNCwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0NCmRhdCA8LSBkYXQgJT4lDQogIHN0X3RyYW5zZm9ybShjcnMgPSA2NTA1KQ0KDQptYXBfNSA8LSANCmdyaWQuYXJyYW5nZShuY29sID0gMiwNCiAgICAgICAgICAgICANCmdncGxvdCgpICsNCiAgZ2VvbV9zZihkYXRhID0gZGF0LCBhZXMoZmlsbD1oaEluY29tZV9tZWQpLCBhbHBoYSA9IDAuOCwgY29sb3IgPSAidHJhbnNwYXJlbnQiKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpcyhhbHBoYSA9IC43NSwNCiAgICAgICAgICAgICAgICAgICAgYmVnaW4gPSAwLjA1LA0KICAgICAgICAgICAgICAgICAgICBlbmQgPSAwLjg1LA0KICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAxLA0KICAgICAgICAgICAgICAgICAgICBkaXNjcmV0ZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICBvcHRpb24gPSAiQiIpICsNCiAgZ2VvbV9zZihkYXRhPW1zcF9ib3VuZGFyeSwNCiAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwNCiAgICAgICAgICBjb2xvciA9ICIjNDc0NzQ3IiwNCiAgICAgICAgICBzaXplID0gLjUpICsNCiAgZ2VvbV9zZihkYXRhPWZpc2huZXRfZG1nLA0KICAgICAgICAgIGZpbGwgPSAidHJhbnNwYXJlbnQiLA0KICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgICBzaXplID0gLjI1KSArDQogIGxhYnModGl0bGUgPSJNZWRpYW4gSG91c2Vob2xkIEluY29tZSIsDQogICAgICAgZmlsbCA9ICJWYWx1ZSAoJCkiLA0KICAgICAgIGNhcHRpb24gPSAiU291cmNlOiAyMDIwIDUtWWVhciBBQ1MiKSArDQogIG1hcFRoZW1lLA0KDQpnZ3Bsb3QoKSArDQogIGdlb21fc2YoZGF0YSA9IGRhdCwgYWVzKGZpbGw9cGN0V2hpdGVfbWVkKSwgYWxwaGEgPSAwLjgsIGNvbG9yID0gInRyYW5zcGFyZW50IikgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXMoYWxwaGEgPSAuNzUsDQogICAgICAgICAgICAgICAgICAgIGJlZ2luID0gMCwNCiAgICAgICAgICAgICAgICAgICAgZW5kID0gMC45LA0KICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAxLA0KICAgICAgICAgICAgICAgICAgICBkaXNjcmV0ZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICBvcHRpb24gPSAiQiIpICsNCiAgZ2VvbV9zZihkYXRhPW1zcF9ib3VuZGFyeSwNCiAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwNCiAgICAgICAgICBjb2xvciA9ICIjNDc0NzQ3IiwNCiAgICAgICAgICBzaXplID0gLjUpICsNCiAgZ2VvbV9zZihkYXRhPWZpc2huZXRfZG1nLA0KICAgICAgICAgIGZpbGwgPSAidHJhbnNwYXJlbnQiLA0KICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgICBzaXplID0gLjI1KSArDQogIGxhYnModGl0bGUgPSIlIFdoaXRlIFBvcHVsYXRpb24iLA0KICAgICAgIGZpbGwgPSAiJSIsDQogICAgICAgY2FwdGlvbiA9ICJTb3VyY2U6IDIwMjAgNS1ZZWFyIEFDUyIpICsNCiAgbWFwVGhlbWUNCikNCmBgYA0KDQpGaW5hbGx5LCB0byBpbmNvcnBvcmF0ZSBjZW5zdXMgdmFyaWFibGVzIEkgc2V0IGVhY2ggY2VsbCBlcXVhbCB0byB0aGUgbWVkaWFuIHZhbHVlIG9mIHRoZSByYXN0ZXIgcGl4ZWxzIHdpdGhpbiBpdCBmb3IgYm90aCBtZWRpYW4gaG91c2Vob2xkIGluY29tZSBhbmQgJSBvZiB0aGUgcG9wdWxhdGluIHRoYXQgaWRlbnRpZmllZCBhcyBXaGl0ZSBpbiAyMDIwLg0KDQpgYGB7ciBleHBvcnQgbWFwcywgaW5jbHVkZSA9IEZBTFNFLCBldmFsID0gRkFMU0V9DQpnZ3NhdmUoIkM6L1VzZXJzL2N0b3duL09uZURyaXZlIC0gUGVubk8zNjUvQ2xhc3Nlcy9DbGFzc2VzX1NlbTRfMjAyM1NwcmluZy9DUExONTA1X1BsYW5uaW5nIGJ5IE51bWJlcnMvQXNzaWdubWVudHMvRmluYWwgUHJvamVjdC9HcmFwaGljcy9NYXBzL1BQX01hcDFfRmlzaG5ldC5wZGYiLCBwbG90ID0gbWFwXzEpDQoNCmdnc2F2ZSgiQzovVXNlcnMvY3Rvd24vT25lRHJpdmUgLSBQZW5uTzM2NS9DbGFzc2VzL0NsYXNzZXNfU2VtNF8yMDIzU3ByaW5nL0NQTE41MDVfUGxhbm5pbmcgYnkgTnVtYmVycy9Bc3NpZ25tZW50cy9GaW5hbCBQcm9qZWN0L0dyYXBoaWNzL01hcHMvUFBfTWFwczJfRG1nLnBkZiIsIHBsb3QgPSBtYXBfMiwgd2lkdGggPSAxMSkNCg0KZ2dzYXZlKCJDOi9Vc2Vycy9jdG93bi9PbmVEcml2ZSAtIFBlbm5PMzY1L0NsYXNzZXMvQ2xhc3Nlc19TZW00XzIwMjNTcHJpbmcvQ1BMTjUwNV9QbGFubmluZyBieSBOdW1iZXJzL0Fzc2lnbm1lbnRzL0ZpbmFsIFByb2plY3QvR3JhcGhpY3MvTWFwcy9QUF9NYXBzM19kc3RuYy5wZGYiLCBwbG90ID0gbWFwXzMsIHdpZHRoID0gMTEpDQoNCmdnc2F2ZSgiQzovVXNlcnMvY3Rvd24vT25lRHJpdmUgLSBQZW5uTzM2NS9DbGFzc2VzL0NsYXNzZXNfU2VtNF8yMDIzU3ByaW5nL0NQTE41MDVfUGxhbm5pbmcgYnkgTnVtYmVycy9Bc3NpZ25tZW50cy9GaW5hbCBQcm9qZWN0L0dyYXBoaWNzL01hcHMvUFBfTWFwczRfVmx1QWJzbnRlZS5wZGYiLCBwbG90ID0gbWFwXzQsIHdpZHRoID0gMTEpDQoNCmdnc2F2ZSgiQzovVXNlcnMvY3Rvd24vT25lRHJpdmUgLSBQZW5uTzM2NS9DbGFzc2VzL0NsYXNzZXNfU2VtNF8yMDIzU3ByaW5nL0NQTE41MDVfUGxhbm5pbmcgYnkgTnVtYmVycy9Bc3NpZ25tZW50cy9GaW5hbCBQcm9qZWN0L0dyYXBoaWNzL01hcHMvUFBfTWFwczVfSW5jbVdodC5wZGYiLCBwbG90ID0gbWFwXzUsIHdpZHRoID0gMTEpDQoNCmdnc2F2ZSgiQzovVXNlcnMvY3Rvd24vT25lRHJpdmUgLSBQZW5uTzM2NS9DbGFzc2VzL0NsYXNzZXNfU2VtNF8yMDIzU3ByaW5nL0NQTE41MDVfUGxhbm5pbmcgYnkgTnVtYmVycy9Bc3NpZ25tZW50cy9GaW5hbCBQcm9qZWN0L0dyYXBoaWNzL01hcHMvUFBfTWFwczZfQ29tbWVyY2lhbC5wZGYiLCBwbG90ID0gbWFwXzYsIHdpZHRoID0gMTEpDQpgYGANCg0KPGJyPg0KDQojIyBQbG90cw0KDQpPbmNlIEkgaGFkIGFsbCBvZiB0aGUgdmFyaWFibGVzIGNyZWF0ZWQgYW5kIG1hcHBlZCwgSSBtYWRlIGEgc2VyaWVzIG9mIGNoYXJ0cyB0byBiZXR0ZXIgdW5kZXJzdGFuZCB0aGUgZGF0YS4NCg0KYGBge3IgZGFtYWdlZCB2cy4gbm90IGNvdW50fQ0KI0hvdyBtYW55IGRhbWFnZWQgZmlzaGVudCBjZWxscyB2cy4gbm90Pw0KY2hhcnRfMiA8LQ0KZ2dwbG90KGRhdCwgYWVzKHggPSBhcy5mYWN0b3IoZGFtYWdlZCksIGZpbGwgPSBhcy5mYWN0b3IoZGFtYWdlZCksIHN0YXQgPSAiY291bnQiKSkgKw0KICBnZW9tX2JhcihhbHBoYSA9IDAuOCkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjZjNhMTA4IiwgIiM0YzAwNzMiKSwNCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiTm90IERhbWFnZWQiLCAiRGFtYWdlZCIpLA0KICAgICAgICAgICAgICAgICAgICBuYW1lID0gIlByZXNlbmNlIG9mXG5EYW1hZ2UiKSArDQogIHhsYWIoIkRhbWFnZWQgdnMuIE5vdCIpICsgDQogIHlsYWIoIkNvdW50IikgKw0KICBsYWJzKHRpdGxlPSJDZWxscyBDb250YWluaW5nIERhbWFnZSIsDQogICAgICAgc3VidGl0bGUgPSAiQ291bnQgb2YgRmlzaG5ldCBDZWxscyB0aGF0IERvIGFuZCBEb24ndCBDb250YWluIERhbWFnZWQgUHJvcGVydGllcyIpICsNCiAgdGhlbWVfYncoKQ0KDQpjaGFydF8yDQpgYGANCg0KUmlnaHQgYXdheSBpdCBpcyBjbGVhciB0aGF0IHRoZXJlIGFyZSBmYXIgbW9yZSB1bmRhbWFnZWQgZmlzaG5ldCBjZWxscyB0aGFuIGRhbWFnZWQgb25lcy4gDQoNCmBgYHtyICUgZGFtYWdlZCwgcmVzdWx0cz0naGlkZSd9DQpjZWxsc193X2RtZyA8LSBhcy5udW1lcmljKHN1bShkYXQkZGFtYWdlZCA9PSAxKSkNCmBgYA0KDQpJbiBmYWN0LCBqdXN0IDIxMyBvdXQgb2YgdGhlIDQsNDMwIGZpc2huZXQgY2VsbHMgKDQuOCUpIGZpc2huZXQgY2VsbHMgY29udGFpbiBkYW1hZ2VkIHByb3BlcnRpZXMuIFRoYXQgc2FtcGxlIHNpemUgaXMgYSBsaXR0bGUgc21hbGwsIHNvIGhvcGVmdWxseSBpdCB3b24ndCBiZSBhIHByb2JsZW0uDQoNCmBgYHtyIGRhbWFnZSBieSBsZXZlbH0NCiNIb3cgbWFueSBwcm9wZXJ0aWVzIHdpdGggZWFjaCBraW5kIG9mIGRhbWFnZT8NCmNoYXJ0XzEgPC0NCmdncGxvdChwYXJjZWxzX2RtZywgYWVzKHggPSBkbWdfbHZsLCBmaWxsID0gZG1nX2x2bCwgc3RhdCA9ICJjb3VudCIpKSArDQogIGdlb21fYmFyKGFscGhhID0gMC44KSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM0YzAwNzMiLCAiI2YzYTEwOCIsICIjZjI3NDA1IiwgIiNkOTNkMDQiKSwNCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiRGVzdHJveWVkIiwgIk1pbm9yIiwgIk1vZGVyYXRlIiwgIlNldmVyZSIpLA0KICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkRhbWFnZVxuTGV2ZWwiKSArDQogIHhsYWIoIkRhbWFnZSBMZXZlbCIpICsgDQogIHlsYWIoIkNvdW50IikgKw0KICBsYWJzKHRpdGxlPSJQcm9wZXJ0eSBEYW1hZ2UgYnkgTGV2ZWwiKSArDQogIHRoZW1lX2J3KCkNCg0KY2hhcnRfMQ0KYGBgDQoNCg0KRXZlbiB0aG91Z2ggSSdtIHdvcmtpbmcgd2l0aCBkYW1hZ2UgYXMgYSBiaW5hcnksIEkgd2FzIGN1cmlvdXMgYWJvdXQgd2hhdCBraW5kIG9mIGRhbWFnZSBpcyBtb3N0IHJlcHJlc2VudGVkIGluIHRoZSBkYXRhLiBQbG90dGluZyB0aGlzIHJldmVhbHMgdGhhdDogIA0KDQoqIDkxOCBvZiB0aGVtIHJlY2VpdmVkICJtaW5vciIgZGFtYWdlICANCg0KKiAyMTYgcmVjZWl2ZWQgIm1vZGVyYXRlIiBkYW1hZ2UgIA0KDQoqIDEyIHJlY2VpdmVkICJzZXZlcmUiIGRhbWFnZSAgDQoNCiogMzYgd2VyZSAiZGVzdHJveWVkIiAgDQoNClRvIGdldCBiYWNrIG9uIHRyYWNrIHRob3VnaCwgaG93IGRvIHRoZSBkYW1hZ2VkIHZzLiBub3QgZGFtYWdlZCBjZWxscyBjb21wYXJlIHRvIGVhY2ggb3RoZXIgZm9yIGVhY2ggdmFyaWFibGUgb2YgaW50ZXJlc3Q/DQoNCmBgYHtyIHBsb3RzIGRhdGEgc3ByZWFkLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQ0KI1Bpdm90IHRvIHZpc3VhbGl6ZSB3aXRoIHZpb2xpbiBwbG90DQpkYXRfcGxvdHZhcnMgPC0gZGF0ICU+JSANCiAgYXMuZGF0YS5mcmFtZSgpICU+JQ0KICAgIGRwbHlyOjpzZWxlY3QoZGFtYWdlZCwgY21tcmNsX3N1bSwgY21tcmNsX2JpbmFyeSwgRElTVF9QUlRTVCwgRElTVF9QT0xDLCB2YWx1ZV9tZWFuLCB2YWx1ZV9sb2csDQogICAgICAgICAgICAgICAgICBhYnNudGVlX3N1bSwgaGhJbmNvbWVfbWVkLCBwY3RXaGl0ZV9tZWQpICU+JSANCiAgICBwaXZvdF9sb25nZXIoY29scyA9IC1kYW1hZ2VkKQ0KDQojdmlvbGluIHBsb3RzDQpjaGFydF8zIDwtDQpnZ3Bsb3QoZGF0X3Bsb3R2YXJzKSArIA0KICAgICBnZW9tX3Zpb2xpbihhZXMoeCA9IGFzLmZhY3RvcihkYW1hZ2VkKSwgDQogICAgICAgICAgICAgICAgICB5ID0gdmFsdWUsIGZpbGwgPSBhcy5mYWN0b3IoZGFtYWdlZCkpKSArIA0KICAgICBmYWNldF93cmFwKH5uYW1lLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICBsYWJzKHg9IkRhbWFnZSBTdGF0dXMiLCB5PSJWYWx1ZSIpICsgDQogICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNmM2ExMDgiLCAiIzRjMDA3MyIpLA0KICAgICBsYWJlbHMgPSBjKCJOb3QgRGFtYWdlZCIsICJEYW1hZ2VkIiksIG5hbWUgPSAiIikgKw0KICBwbG90VGhlbWUNCg0KY2hhcnRfMw0KYGBgDQoNClRoZXNlIHZpb2xpbiBwbG90cyBzaG93IHRoYXQgc29tZSB2YXJpYWJsZXMgZXhoaWJpdCBncmVhdGVyIGRpZmZlcmVuY2UgYWNyb3NzIGRhbWFnZSBzdGF0dXMgdGhhbiBvdGhlcnMuIEl0IGFsc28gc2hvd3MgdGhlIGltcG9ydGFuY2Ugb2YgbG9nIGFkanVzdGluZyB0aGUgdmFsdWUgdmFyaWFibGUgdG8gYmUgYWJsZSB0byBtYWtlIG1lYW5pbmdmdWwgY29tcGFyaXNvbnMgYnkgY29tcHJlc3Npbmcgb3V0bGllcnMuDQoNCjxicj4NCg0KIyBWYXJpYWJsZSBTZWxlY3Rpb24NCg0KQmFzZWQgb24gdGhlIGRhdGEgZW5naW5lZXJpbmcgYW5kIGluaXRpYWwgZXhwbG9yYXRpb24sIHRoZXNlIGFyZSB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUgY2FuZGlkYXRlcyBJIHdvdWxkIGxpa2UgdG8gaW5jbHVkZSBpbiBhIGJpbm9taWFsIHJlZ3Jlc3Npb24gbW9kZWw6DQoNCiogQ29uY2VudHJhdGlvbiBvZiBjb21tZXJjaWFsIHByb3BlcnR5IGBjbW1yY2xfc3VtYCAgDQoqIExvY2F0aW9uIG9uIGEgY29tbWVyY2lhbCBjb3JyaWRvciBgY21tcmNsX2JpbmFyeWAgKGFzIGEgYmluYXJ5IHZhcmlhYmxlKSAgDQoqIERpc3RhbmNlIGZyb20gUHJvdGVzdCBTaXRlcyBgRElTVF9QUlRTVGAgIA0KKiBEaXN0YW5jZSBmcm9tIFBvbGljZSBTdGF0aW9ucyBgRElTVF9QT0xDYCAgDQoqIE1lYW4gcHJvcGVydHkgdmFsdWUgYHZhbHVlX21lYW5gDQoqIExvZyBhZGp1c3RlZCBwcm9wZXJ0eSB2YWx1ZSBgdmFsdWVfbG9nYCAgDQoqIENvbmNlbnRyYXRpb24gb2YgQWJzZW50ZWUgT3duZXJzaGlwIGBhYnNudGVlX3N1bWAgIA0KKiAlIG9mIHBvcHVsYXRpb24gdGhhdCBpcyBXaGl0ZSBgcGN0V2hpdGVfbWVkYCAgDQoqIE1lZGlhbiBIb3VzZWhvbGQgSW5jb21lIGBoaEluY29tZV9tZWRgICANCg0KVGhlIGV4cGxvcmF0b3J5IGFuYWx5c2lzIHN1Z2dlc3RzIHRoYXQgdGhlc2UgdmFyaWFibGVzIHJlbGF0ZSB0byBwcm90ZXN0IHByb3BlcnR5IGRhbWFnZS4gSG93ZXZlciwgSSBuZWVkIHRvIG1ha2Ugc3VyZSBub25lIG9mIHRoZW0gYXJlIHRvbyBjb3JyZWxhdGVkIHdpdGggdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBvciBlYWNoIG90aGVyIChjb2xsaW5lYXIpIHRvIGF2b2lkIG1vZGVsIGVycm9yLg0KDQo8YnI+DQoNCiMjIFRlc3QgZm9yIENvcnJlbGF0aW9uDQoNCmBgYHtyIGNvcnJlbGF0aW9uIG1hdHJpeCwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9DQojbWFrZSBtYXRyaXggb2YgdmFyaWFibGVzIHRvIHRlc3QNCmNvcnJfdmFycyA8LSBkYXQgJT4lIA0KICBhcy5kYXRhLmZyYW1lKCkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC11bmlxdWVJRCwgLWdlb21ldHJ5LCAtZG1nX1NVTSkgJT4lDQogIG11dGF0ZShjbW1yY2xfYmluYXJ5ID0gYXMuaW50ZWdlcihjbW1yY2xfYmluYXJ5KSwNCiAgICAgICAgIGRhbWFnZWQgPSBhcy5pbnRlZ2VyKGRhbWFnZWQpKSAlPiUgDQogIHJlbmFtZSgiQWJzZW50ZWUgT3duZXJzaGlwIiA9IGFic250ZWVfc3VtLA0KICAgICAgICAgIlByb3BlcnR5IFZhbHVlIiA9IHZhbHVlX21lYW4sDQogICAgICAgICAiUHJvcGVydHkgVmFsdWUgKGxvZykiID0gdmFsdWVfbG9nLA0KICAgICAgICAgIkRpc3RhbmNlIGZyb20gUHJvdGVzdCBTaXRlcyIgPSBESVNUX1BSVFNULA0KICAgICAgICAgIkRpc3RhbmNlIGZyb20gUG9saWNlIFN0YXRpb25zIiA9IERJU1RfUE9MQywNCiAgICAgICAgICJDb21tZXJjaWFsIFByb3BlcnRpZXMiID0gY21tcmNsX3N1bSwNCiAgICAgICAgICJDb21tZXJjaWFsIENvcnJpZG9ycyIgPSBjbW1yY2xfYmluYXJ5LA0KICAgICAgICAgIlByZXNlbmNlIG9mIERhbWFnZWQgUHJvcGVydGllcyIgPSBkYW1hZ2VkLA0KICAgICAgICAgIk1lZGlhbiBIb3VzZWhvbGQgSW5jb21lIiA9IGhoSW5jb21lX21lZCwNCiAgICAgICAgICJQb3AgJSBXaGl0ZSIgPSBwY3RXaGl0ZV9tZWQpDQoNCiNjb21wdXRlIGNvcnJlbGF0aW9uIG1hdHJpeA0KY29ybWF0cml4IDwtIGNvcihjb3JyX3ZhcnMpICU+JSANCiAgcm91bmQoLiwgMikNCg0KI3Bsb3QgYSBjb3JyZWxvZ3JhbQ0KY2hhcnRfNCA8LQ0KZ2djb3JycGxvdChjb3JtYXRyaXgsDQogICAgICAgICAgIG1ldGhvZCA9ICJzcXVhcmUiLA0KICAgICAgICAgICBoYy5vcmRlciA9IEZBTFNFLA0KICAgICAgICAgICBjb2xvcnMgPSBjKCIjZjNhMTA4IiwgIndoaXRlIiwgIiM0YzAwNzMiKSwNCiAgICAgICAgICAgb3V0bGluZS5jb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgIHR5cGUgPSAibG93ZXIiLA0KICAgICAgICAgICB0bC5jZXggPSA5LA0KICAgICAgICAgICBsYWIgPSBUUlVFKQ0KDQpjaGFydF80DQpgYGANCg0KTWVkaWFuIEhvdXNlaG9sZCBJbmNvbWUgaXMgY29sbGluZWFyIHdpdGggUG9wdWxhdGlvbiAlIFdoaXRlIGFuZCBkaXN0YW5jZSBmcm9tIHBvbGljZSBzdGF0aW9ucy4gVGhlcmVmb3JlLCBJIHdpbGwgaW5jbHVkZSAlIFdoaXRlIGluIG1vZGVscyBtb3ZpbmcgZm9yd2FyZCBiZWNhdXNlIGl0J3Mgc2xpZ2h0bHkgbW9yZSBjb3JyZWxhdGVkIHdpdGggcHJlc2VuY2Ugb2YgZGFtYWdlZCBwcm9wZXJ0aWVzIGFuZCB3aWxsIG1ha2UgZm9yIGxlc3MgY29tcGxpY2F0ZWQgbW9kZWxpbmcuDQoNCkZvcnR1bmF0ZWx5LCB0aGUgcmVzdCBvZiB0aGVzZSB2YXJpYWJsZXMgYXZvaWQgY29saW5lYXJpdHkgd2l0aCBlYWNoIG90aGVyLiBUaGUgc3Ryb25nZXN0IGNvcnJlbGF0aW9uIGlzIGJldHdlZW4gZGlzdGFuY2UgZnJvbSBwcm90ZXN0cyBhbmQgZGlzdGFuY2UgZnJvbSBwb2xpY2Ugc3RhdGlvbnMuIFRoaXMgbWFrZXMgc2Vuc2Ugc2luY2Ugc29tZSBwcm90ZXN0cyBvY2N1cnJlZCBhdCBwb2xpY2Ugc3RhdGlvbnMuIEhvd2V2ZXIsIG5vdCBhbGwgcHJvdGVzdHMgZGlkIHNvIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZW0gaXMgc3RpbGwgYmVsb3cgMC41LCBtZWFuaW5nIGJvdGggY2FuIHN0YXkgaW4gdGhlIG1vZGVsIHdpdGhvdXQgd29ycnkuDQoNCkFkZGl0aW9uYWxseSwgd2Ugc2VlIHRoYXQgdGhlIHZhcmlhYmxlcyBtb3N0IGNvcnJlbGF0ZWQgd2l0aCBwcm9wZXJ0eSBkYW1hZ2UgYXJlOiANCg0KKiBDb21tZXJjaWFsIENvcnJpZG9ycyAgDQoqIERpc3RhbmNlIGZyb20gcG9saWNlIHN0YXRpb25zICANCiogRGlzdGFuY2UgZnJvbSBwcm90ZXN0IHNpdGVzICANCiogQWJzZW50ZWUgT3duZXJzaGlwLCBhbmQgIA0KKiBQcm9wZXJ0eSBWYWx1ZSAgDQoNCmBgYHtyIGV4cG9ydCBjaGFydHMsIGluY2x1ZGUgPSBGQUxTRSwgZXZhbCA9IEZBTFNFfQ0KZ2dzYXZlKCJDOi9Vc2Vycy9jdG93bi9PbmVEcml2ZSAtIFBlbm5PMzY1L0NsYXNzZXMvQ2xhc3Nlc19TZW00XzIwMjNTcHJpbmcvQ1BMTjUwNV9QbGFubmluZyBieSBOdW1iZXJzL0Fzc2lnbm1lbnRzL0ZpbmFsIFByb2plY3QvR3JhcGhpY3MvQ2hhcnRzL1BQX0NoYXJ0MV9EbWdieUx2bC5wZGYiLCBwbG90ID0gY2hhcnRfMSwgd2lkdGggPSAxMSkNCg0KZ2dzYXZlKCJDOi9Vc2Vycy9jdG93bi9PbmVEcml2ZSAtIFBlbm5PMzY1L0NsYXNzZXMvQ2xhc3Nlc19TZW00XzIwMjNTcHJpbmcvQ1BMTjUwNV9QbGFubmluZyBieSBOdW1iZXJzL0Fzc2lnbm1lbnRzL0ZpbmFsIFByb2plY3QvR3JhcGhpY3MvQ2hhcnRzL1BQX0NoYXJ0Ml9EbWdDb3VudC5wZGYiLCBwbG90ID0gY2hhcnRfMiwgd2lkdGggPSAxMSkNCg0KZ2dzYXZlKCJDOi9Vc2Vycy9jdG93bi9PbmVEcml2ZSAtIFBlbm5PMzY1L0NsYXNzZXMvQ2xhc3Nlc19TZW00XzIwMjNTcHJpbmcvQ1BMTjUwNV9QbGFubmluZyBieSBOdW1iZXJzL0Fzc2lnbm1lbnRzL0ZpbmFsIFByb2plY3QvR3JhcGhpY3MvQ2hhcnRzL1BQX0NoYXJ0M19WaW9saW4ucGRmIiwgcGxvdCA9IGNoYXJ0XzMsIHdpZHRoID0gMTEpDQoNCmdnc2F2ZSgiQzovVXNlcnMvY3Rvd24vT25lRHJpdmUgLSBQZW5uTzM2NS9DbGFzc2VzL0NsYXNzZXNfU2VtNF8yMDIzU3ByaW5nL0NQTE41MDVfUGxhbm5pbmcgYnkgTnVtYmVycy9Bc3NpZ25tZW50cy9GaW5hbCBQcm9qZWN0L0dyYXBoaWNzL0NoYXJ0cy9QUF9DaGFydDRfQ29yclBsb3QucGRmIiwgcGxvdCA9IGNoYXJ0XzQsIHdpZHRoID0gMTEpDQpgYGANCg0KPGJyPg0KDQojIExvZ2lzdGljIFJlZ3Jlc3Npb25zDQoNCkkgY2hvc2UgdG8gdXNlIGJpbm9taWFsIGxvZ2lzdGljIHJlZ3Jlc3Npb24gZm9yIHRoaXMgYXNzaWdubWVudCBiZWNhdXNlIGl0IGlzIGEgdHlwZSBvZiBzdGF0aXN0aWNhbCBtb2RlbCB0aGF0IGlzIHdlbGwgc3VpdGVkIHRvIGFuYWx5emluZyByZWxhdGlvbnNoaXBzIGJldHdlZW4gYSBiaW5hcnkgcmVzcG9uc2UgdmFyaWFibGUgYW5kIG9uZSBvciBtb3JlIHByZWRpY3RvciB2YXJpYWJsZXMuIEl0IGVzdGltYXRlcyB0aGUgcHJvYmFiaWxpdHkgb2YgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIHRha2luZyBvbmUgb2YgdGhlIHR3byBwb3NzaWJsZSB2YWx1ZXMgKGluIHRoaXMgY2FzZSBkYW1hZ2VkIG9yIG5vdCBkYW1hZ2VkKSBiYXNlZCBvbiB0aGUgdmFsdWVzIG9mIHRoZSBwcmVkaWN0b3IgdmFyaWFibGVzLg0KDQpCZWZvcmUgbWFraW5nIGFueSBtb2RlbHMsIEkgZmlyc3QgdHVybmVkIHRoZSBiaW5hcnkgdmFyaWFibGVzIGludG8gZmFjdG9ycy4gVGhlc2UgYXJlIG15IGRlcGVkZW50IGRhbWFnZSB2YXJpYWJsZSBhbmQgdGhlIGNvbW1lcmNpYWwgY29ycmlkb3IgdmFyaWFibGUuDQoNCmBgYHtyIGRhdCBpbnRvIGZhY3Rvcn0NCmRhdCRkYW1hZ2VkIDwtIGFzLmZhY3RvcihkYXQkZGFtYWdlZCkgDQpkYXQkY21tcmNsX2JpbmFyeSA8LSBhcy5mYWN0b3IoZGF0JGNtbXJjbF9iaW5hcnkpDQoNCiNDb252ZXJ0IHRoZSBkaXN0YW5jZSB2YXJpYWJsZXMgdW5pdHMgZnJvbSBmZWV0IHRvIG1pbGVzDQpkYXQkRElTVF9QT0xDIDwtIGRhdCRESVNUX1BPTEMvNTI4MA0KZGF0JERJU1RfUFJUU1QgPC0gZGF0JERJU1RfUFJUU1QvNTI4MA0KYGBgDQoNClRoZSBmaXJzdCBtb2RlbCBpbmNsdWRlcyBhbGwgZWlnaHQgdmFyaWFibGVzIG9mIGludGVyZXN0Og0KDQoqIGBjbW1yY2xfYmluYXJ5YCAgDQoqIGBjbW1yY2xfc3VtYCAgDQoqIGBESVNUX1BSVFNUYCAgDQoqIGBESVNUX1BPTENgICANCiogYHZhbHVlX21lYW5gICANCiogYHZhbHVlX2xvZ2AgIA0KKiBgYWJzbnRlZV9zdW1gICANCiogYHBjdFdoaXRlX21lZGANCg0KIyMgTW9kZWwgMQ0KDQoNCmBgYHtyIG1vZDF9DQptb2QxIDwtIGdsbShkYW1hZ2VkIH4gY21tcmNsX3N1bSArIGNtbXJjbF9iaW5hcnkgKyBESVNUX1BSVFNUICsgRElTVF9QT0xDICsgdmFsdWVfbWVhbiArIHZhbHVlX2xvZyArIGFic250ZWVfc3VtICsgcGN0V2hpdGVfbWVkLCANCiAgICAgICAgICAgIGZhbWlseT0iYmlub21pYWwiKGxpbms9ImxvZ2l0IiksIGRhdGEgPSBkYXQpDQpzdW1tYXJ5KG1vZDEpDQpgYGANClRoZSByZXN1bHRzIGluZGljYXRlOiAgDQoNCiogVGhlIHAtdmFsdWVzIGluZGljYXRlIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSBmb3IgYWxsIG9mIHRoZSB2YXJpYWJsZXMgZXhjZXB0IGZvciBgdmFsdWVfbWVhbmAuICANCiogVGhlIEFJQyBvZiB0aGlzIG1vZGVsIGlzIDEyNDQuNy4gV2hlbiBzZWxlY3RpbmcgYmV0d2VlbiByZWdyZXNzaW9uIG1vZGVscywgdGhlIG1vZGVsIHdpdGggdGhlIGxvd2VyIEFJQyBiZXR0ZXIgZml0cyB0aGUgZGF0YS4gIA0KDQojIyMgQXV0b21hdGVkIFZhcmlhYmxlIFNlbGVjdGlvbg0KDQpJdCBhcHBlYXJzIHRoYXQgYHZhbHVlX21lYW5gIGlzIG5vdCBzaWduaWZpY2FudCBhbmQgdGhlcmVmb3JlIHNob3VsZCBiZSBleGNsdWRlZCBmcm9tIHRoZSBtb2RlbC4gTGV0J3MgY29uZmlybSB2aWEgYXV0b21hdGVkIHZhcmlhYmxlIHNlbGVjdGlvbiB3aXRoIGBkcm9wMWAuDQoNCmBgYHtyIGRyb3AxfQ0KZHJvcDEobW9kMSwgdGVzdD0iQ2hpc3EiKQ0KYGBgDQpUaGUgYGRyb3AxYCByZXN1bHRzIGluZGljYXRlIHRoYXQgcmVtb3ZpbmcgYHZhbHVlX21lYW5gIHdvdWxkIG5vdCBpbmNyZWFzZSB0aGUgbW9kZWwncyBkZXZpYW5jZSBhbmQgd291bGQgYWN0dWFsbHkgbG93ZXIgaXRzIEFJQywgbWVhbmluZyBpdCB3b3VsZCBpbXByb3ZlIHRoZSBtb2RlbCdzIGZpdC4NCg0KIyMgTW9kZWwgMg0KDQpTbywgd2hhdCBjaGFuZ2VzIGlmIGB2YWx1ZV9tZWFuYCBpcyBleGNsdWRlZD8NCg0KYGBge3IgbW9kMn0NCm1vZDIgPC0gZ2xtKGRhbWFnZWQgfiBjbW1yY2xfc3VtICsgY21tcmNsX2JpbmFyeSArIERJU1RfUFJUU1QgKyBESVNUX1BPTEMgKyB2YWx1ZV9sb2cgKyBhYnNudGVlX3N1bSArIHBjdFdoaXRlX21lZCwgDQogICAgICAgICAgICBmYW1pbHk9ImJpbm9taWFsIihsaW5rPSJsb2dpdCIpLCBkYXRhID0gZGF0KQ0Kc3VtbWFyeShtb2QyKQ0KYGBgDQpHb29kIG5ld3MsIGRyb3BwaW5nIGB2YWx1ZV9tZWFuYCBkZWNyZWFzZWQgdGhlIEFJQyBieSAyIGZyb20gTW9kZWwgMSdzIEFJQyBvZiAxMjQ0LjcuIFRoaXMgbWVhbnMgTW9kZWwgMiBkZXNjcmliZXMgdGhlIGRhdGEgYmV0dGVyIHRoYW4gTW9kZWwgMSBidXQgd2l0aCAxIGZld2VyIHZhcmlhYmxlLg0KDQpIb3dldmVyLCBgcGN0V2hpdGVfbWVkYCBpcyBzdGlsbCBsZXNzIHNpZ25pZmljYW50IHRoYW4gdGhlIG90aGVyIHZhcmlhYmxlcy4gV2hhdCBoYXBwZW5zIGlmIHRoaXMgdmFyaWFibGUgaXMgZXhjbHVkZWQgZnJvbSB0aGUgbmV4dCBtb2RlbD8gQmFzZWQgb24gdGhlIGBkcm9wMWAgcmVzdWx0cywgdGhlIEFJQyBzaG91bGQgaW5jcmVhc2Ugc2xpZ2h0bHkgKGJ5IDQ/KS4NCg0KIyMgTW9kZWwgMw0KDQpgYGB7ciBtb2QzfQ0KbW9kMyA8LSBnbG0oZGFtYWdlZCB+IGNtbXJjbF9zdW0gKyBjbW1yY2xfYmluYXJ5ICsgRElTVF9QUlRTVCArIERJU1RfUE9MQyArIHZhbHVlX2xvZyArIGFic250ZWVfc3VtLCANCiAgICAgICAgICAgIGZhbWlseT0iYmlub21pYWwiKGxpbms9ImxvZ2l0IiksIGRhdGEgPSBkYXQpDQpzdW1tYXJ5KG1vZDMpDQpgYGANClRoZSBBSUMgaW5jcmVhc2VkIHNsaWdodGx5IHRoaXMgdGltZSAoYnkgMy44KSBmcm9tIE1vZGVsIDIncyBBSUMgb2YgMTI0Mi43LiBTaW5jZSB0aGlzIGlzIGEgbWlub3IgaW5jcmVhc2UsIGEgbW9kZWwgd2l0aG91dCBgdmFsdWVfbWVhbmAgb3IgYHBjdFdoaXRlX21lZGAgZnVuY3Rpb25hbGx5IGRlc2NyaWJlcyB0aGUgZGF0YSBhcyBhIHdlbGwgYXMgYSBtb2RlbCB3aXRoIHRoZW0uDQoNCk5vdyBhbGwgb2YgdGhlIHZhcmlhYmxlcyBoYXZlIGF0IGxlYXN0IGEgaGlnaCBsZXZlbCBvZiBzaWduaWZpY2FuY2UuIEhvd2V2ZXIsIGBhYnNudGVlX3N1bWAgaXMgbGVzcyBzaWduaWZpY2FudCB0aGFuIHRoZSBvdGhlcnMuIFdoYXQgaGFwcGVucyBpZiBgYWJzbnRlZV9zdW1gIGlzIGRyb3BwZWQgZnJvbSB0aGUgbW9kZWw/DQoNCg0KIyMgTW9kZWwgNA0KDQpgYGB7ciBtb2Q0fQ0KbW9kNCA8LSBnbG0oZGFtYWdlZCB+IGNtbXJjbF9zdW0gKyBjbW1yY2xfYmluYXJ5ICsgRElTVF9QUlRTVCArIERJU1RfUE9MQyArIHZhbHVlX2xvZywgDQogICAgICAgICAgICBmYW1pbHk9ImJpbm9taWFsIihsaW5rPSJsb2dpdCIpLCBkYXRhID0gZGF0KQ0Kc3VtbWFyeShtb2Q0KQ0KYGBgDQpUaGlzIHRpbWUsIGFsbCBvZiB0aGUgdmFyaWFibGVzIGFyZSBoaWdobHkgc2lnbmlmaWNhbnQgYW5kIHRoZSBBSUMgaGFzIGluY3JlYXNlZCBieSA3LjUgZnJvbSB0aGUgcHJldmlvdXMgbW9kZWwncyBBSUMgb2YgMTI0Ni41Lg0KDQpCZWZvcmUgc2VsZWN0aW5nIGEgZmluYWwgbW9kZWwsIHdhcyBgcGN0V2hpdGVfbWVkYCBhY3R1YWxseSBhIGJldHRlciBwcmVkaWN0b3IgdGhhbiBpdHMgY29sbGluZWFyIHBhaXIgYGhoSW5jb21lX21lZGA/DQoNCg0KIyMgTW9kZWwgNQ0KDQpgYGB7ciBtb2Q1fQ0KbW9kNSA8LSBnbG0oZGFtYWdlZCB+IGNtbXJjbF9zdW0gKyBjbW1yY2xfYmluYXJ5ICsgRElTVF9QUlRTVCArIERJU1RfUE9MQyArIHZhbHVlX2xvZyArIGFic250ZWVfc3VtICsgaGhJbmNvbWVfbWVkLCANCiAgICAgICAgICAgIGZhbWlseT0iYmlub21pYWwiKGxpbms9ImxvZ2l0IiksIGRhdGEgPSBkYXQpDQpzdW1tYXJ5KG1vZDUpDQpgYGANClJlcGxhY2luZyBgcGN0V2hpdGVfbWVkYCB3aXRoIGBoaEluY29tZV9tZWRgIGluIHRoZSBsYXN0IG1vZGVsIHRoYXQgaXQgd2FzIHBhcnQgb2YgKE1vZGVsIDIpIHNob3dzIHRoYXQgaXQgaW4gZmFjdCBpcyBsZXNzIHNpZ25pZmljYW50IG9mIGEgcHJlZGljdG9yLiBUaGlzIGZpZnRoIG1vZGVsJ3MgQUlDIGlzIGhpZ2hlciB0aGFuIHRoYXQgb2YgdGhlIG1vZGVsIHRoYXQgaW5jbHVkZWQgJSBXaGl0ZSwgbWVhbmluZyBNb2RlbCAyIGRlc2NyaWJlZCB0aGUgZGF0YSBiZXR0ZXIgdGhhbiBNb2RlbCA1IGRvZXMuDQoNClRpbWUgdG8gc2VsZWN0IHRoZSBmaW5hbCBtb2RlbC4NCg0KDQojIyBTZWxlY3RpbmcgYSBGaW5hbCBNb2RlbA0KDQpDb21wYXJpbmcgdGhlIGZpdCBvZiB0aGUgbW9kZWxzIHdpdGggYGFub3ZhYCBoZWxwcyBkZXRlcm1pbmVzIHdoaWNoIG1vZGVsIHRvIHNlbGVjdCBhcyB0aGUgZmluYWwgbW9kZWwuIEJlY2F1c2UgYGFub3ZhYCBjYW4gb25seSBjb21wYXJlIG5lc3RlZCBtb2RlbHMsIE1vZGVsIDUgaXMgbm90IGluY2x1ZGVkLiBUaGlzIGlzIG9rIGJlY2F1c2UgTW9kZWwgNSB3YXMgdGhlIHdlYWtlc3QgbW9kZWwgYW55d2F5Lg0KDQpgYGB7ciBDaGVjayBmaXQgd2l0aCBBTk9WQX0NCmFub3ZhKG1vZDEsIG1vZDIsIG1vZDMsIG1vZDQsIHRlc3Q9IkNoaXNxIikNCmBgYA0KVGhlIEFuYWx5c2lzIG9mIERldmlhbmNlIHRhYmxlIGZyb20gQU5PVkEgY29tcGFyZXMgdGhlIGZpdCBvZiB0aGUgbW9kZWxzIGFnYWluc3QgZWFjaCBvdGhlci4gVGhlIHAtdmFsdWVzIGluZGljYXRlIHRoYXQgTW9kZWwgMiBkb2VzIG5vdCBkZXNjcmliZSB0aGUgZGF0YSBtZWFuaW5nZnVsbHkgZGlmZmVyZW50bHkgdGhhbiBNb2RlbCAxLiBIb3dldmVyLCB0aGV5IHNob3cgdGhhdCBNb2RlbCAzIGRlc2NyaWJlcyB0aGUgZGF0YSBtZWFuaW5nZnVsbHkgZGlmZmVyZW50bHkgdGhhbiBNb2RlbCAyIGFuZCBNb2RlbCA0IGRlc2NyaWJlcyB0aGUgZGF0YSBzaWduaWZpY2FudGx5IGRpZmZlcmVudGx5IHRoYW4gTW9kZWwgMy4gQmVjYXVzZSB0aGUgc2Vjb25kIG1vZGVsJ3MgZGV2aWFuY2UgaXMgc21hbGxlciB0aGFuIHRoYXQgb2YgTW9kZWxzIDMgYW5kIDQgYW5kIHRoZSBzYW1lIGFzIE1vZGVsIDEsIE1vZGVsIDIgZGVzY3JpYmVzIHRoZSBkYXRhIHRoZSBiZXN0IHdpdGggdGhlIGZld2VzdCBwb3NzaWJsZSB2YXJpYWJsZXMuDQoNCkhvd2V2ZXIsIHRoZSBkZXZpYW5jZSBvZiBhbGwgbW9kZWxzIGlzIHNtYWxsZXIgdGhhbiB0aGUgbnVsbCBkZXZpYW5jZSBvZiAxNjUyLjIuIFNvLCBldmVyeSBtb2RlbCBkZXNjcmliZXMgdGhlIHZhcmlhdGlvbiBpbiB0aGUgZGF0YSBiZXR0ZXIgdGhhbiBhbiBpbnRlcmNlcHQgb25seSBtb2RlbC4NCg0KYGBge3Igc3RhcmdhemVyLCByZXN1bHRzPSdhc2lzJ30NCnN0YXJnYXplcihtb2QxLCBtb2QyLCBtb2QzLCBtb2Q0LCB0eXBlPSJodG1sIiwgZGlnaXRzID0gMiwgc2luZ2xlLnJvdyA9IEZBTFNFLCBvdXQgPSAiQzovVXNlcnMvY3Rvd24vT25lRHJpdmUgLSBQZW5uTzM2NS9DbGFzc2VzL0NsYXNzZXNfU2VtNF8yMDIzU3ByaW5nL0NQTE41MDVfUGxhbm5pbmcgYnkgTnVtYmVycy9Bc3NpZ25tZW50cy9GaW5hbCBQcm9qZWN0L0dyYXBoaWNzL0NoYXJ0cy9QUF9TdGFyZ2F6ZXIuaHRtbCIpDQpgYGANCjxicj4NCg0KTW9kZWwgMiBoYXMgdGhlIGxvd2VzdCBBSUMgb2YgYWxsIHRoZSBtb2RlbHMgYW5kIGFsbCBvZiBpdHMgdmFyaWFibGVzIGFyZSBzaWduaWZpY2FudC4gVGhlcmVmb3JlLCBNb2RlbCAyIGlzIHNlbGVjdGVkIGFzIHRoZSBmaW5hbCBtb2RlbC4NCg0KPGJyPg0KPGJyPg0KDQojIFJlZ3Jlc3Npb24gSW50ZXJwcmV0YXRpb24NCg0KU28gd2hhdCBkbyB0aGVzZSByZWdyZXNzaW9uIHJlc3VsdHMgbWVhbiBhbnl3YXk/DQoNCiMjIENvZWZmaWNpZW50cw0KDQpgYGB7ciBpbnRlcnByZXQgY29lZmljaWVudCBtb2RfQ2N9DQojaWYgZXhwKGNvZWYpID0gLjg6ICBhIHVuaXQgaW5jcmVhc2UgaW4gWCBpcyBhc3NvY2lhdGVkIHdpdGggDQojYSAyMCUgZGVjbGluZSBpbiB0aGUgb2RkcyByYXRpbw0KI2lmIGV4cChjb2VmKSAgPSAxLjU6ICBhIHVuaXQgaW5jcmVhc2UgaW4gWCBpcyBhc3NvY2lhdGVkIHdpdGggDQojYSA1MCUgaW5jcmVhc2UgaW4gdGhlIG9kZHMgcmF0aW8NCjEwMCAqIChleHAoY29lZihtb2QyKSktMSkNCmBgYA0KDQpUaGUgY29lZmZpY2llbnRzIG9mIHRoZSBtb2RlbCBzdWdnZXN0IHRoYXQ6DQoNCiogQWxsIGVsc2UgZXF1YWwsIGEgb25lIHVuaXQgaW5jcmVhc2UgaW4gdGhlIGFyZWEgb2YgY29tbWVyY2lhbCBwcm9wZXJ0aWVzIGluIGEgZmlzaG5ldCBjZWxsICoqaW5jcmVhc2VzKiogdGhlIG9kZHMgcmF0aW8gb2YgYSBjZWxsIGNvbnRhaW5pbmcgZGFtYWdlZCBwcm9wZXJ0aWVzIGJ5IDIuMSUuICANCg0KKiBBbGwgZWxzZSBlcXVhbCwgdGhlIG9kZHMgcmF0aW8gb2YgYSBjZWxsIG9uIGEgY29tbWVyY2lhbCBjb3JyaWRvciBiZWluZyBkYW1hZ2VkIGlzIDQxMS44JSAqKmhpZ2hlcioqIHRoYW4gZm9yIGEgY2VsbCBub3Qgb24gYSBjb21tZXJjaWFsIGNvcnJpZG9yLiAgDQoNCiogQWxsIGVsc2UgZXF1YWwsIGEgb25lIHVuaXQgKDEgbWlsZSkgaW5jcmVhc2UgaW4gZGlzdGFuY2UgZnJvbSBhIHByb3Rlc3Qgc2l0ZSAqKmRlY3JlYXNlcyoqIHRoZSBvZGRzIHJhdGlvIG9mIGEgY2VsbCBjb250YWluaW5nIGRhbWFnZWQgcHJvcGVydGllcyBieSA0NS4zJS4NCg0KKiBBbGwgZWxzZSBlcXVhbCwgYSBvbmUgdW5pdCAoMSBtaWxlKSBpbmNyZWFzZSBpbiBkaXN0YW5jZSBmcm9tIGEgcG9saWNlIHN0YXRpb24gKipkZWNyZWFzZXMqKiB0aGUgb2RkcyByYXRpbyBvZiBhIGNlbGwgY29udGFpbmluZyBkYW1hZ2VkIHByb3BlcnRpZXMgYnkgMzcuOSUuDQoNCiogQWxsIGVsc2UgZXF1YWwsIGEgb25lIHVuaXQgaW5jcmVhc2UgaW4gcHJvcGVydHkgdmFsdWUgKippbmNyZWFzZXMqKiB0aGUgb2RkcyByYXRpbyBvZiBhIGNlbGwgY29udGFpbmluZyBkYW1hZ2VkIHByb3BlcnRpZXMgYnkgMC4yJSAoMTUuOC8xMDAgYmVjYXVzZSB0aGUgdmFyaWFibGUgaXMgbG9nLWFkanVzdGVkKS4NCg0KKiBBbGwgZWxzZSBlcXVhbCwgYSB1bml0IGluY3JlYXNlIGluIHRoZSBwcmVzZW5jZSBvZiBhYnNlbnRlZSBvd25lZCBwcm9wZXJ0aWVzICoqaW5jcmVhc2VzKiogdGhlIG9kZHMgcmF0aW8gb2YgYSBjZWxsIGNvbnRhaW5pbmcgZGFtYWdlZCBwcm9wZXJ0aWVzIGJ5IDEuNSUuDQoNCiogQWxsIGVsc2UgZXF1YWwsIGEgdW5pdCAoMSUpIGluY3JlYXNlIGluIHRoZSBzaGFyZSBvZiBXaGl0ZSByZXNpZGVudHMgaW4gYSBjZWxsICoqZGVjcmVhc2VzKiogdGhlIG9kZHMgcmF0aW8gb2YgYSBjZWxsIGNvbnRhaW5pbmcgZGFtYWdlZCBwcm9wZXJ0aWVzIGJ5IDU5LjMlLg0KDQpXaGlsZSBhbGwgb2YgdGhlc2UgdmFyaWFibGVzIGFyZSBzaWduaWZpY2FudCwgaXQgaXMgd29ydGggbm90aW5nIHRoZSB2YXJpYWJsZXMgd2l0aCB0aGUgbGFyZ2VzdCBjb2VmZmljaWVudHMuIFRoZXNlIGFyZSBwcmVzZW5jZSBvZiBhIGNvbW1lcmNpYWwgY29ycmlkb3IgYGNtbXJjbF9iaW5hcnkxYCwgZGlzdGFuY2UgZnJvbSBhIHByb3Rlc3Qgc2l0ZSBgRElTVF9QUlRTVGAgb3IgcG9saWNlIHN0YXRpb24gYERJU1RfUE9MQ2AsIGFuZCB0aGUgc2hhcmUgb2YgcG9wdWxhdGlvbiBpbiBhIGdpdmVuIGNlbGwgdGhhdCdzIFdoaXRlIGBwY3RXaGl0ZV9tZWRgLg0KDQpJdCBpcyBhbHNvIGltcG9ydGFudCB0byBub3RlIHRoYXQgdGhlIGNvZWZmaWNpZW50IGZvciB0aGUgaW50ZXJjZXB0IGlzIHF1aXRlIGxhcmdlLCBtZWFuaW5nIHRoZXJlIGlzIHN0aWxsIG11Y2ggb2YgdGhlIHZhcmlhdGlvbiBpbiB0aGUgZGF0YSB0aGF0IHRoZSBzZWxlY3RlZCB2YXJpYWJsZXMgZG8gbm90IGV4cGxhaW4uDQoNClVsdGltYXRlbHksIHRoZSBtb3N0IGltcG9ydGFudCByZXN1bHQgb2YgcnVubmluZyB0aGVzZSBtb2RlbHMgaXMgdGhlIGFiaWxpdHkgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCBhIG1vZGVsIHRoYXQgb25seSBpbmNsdWRlcyBkaXN0YW5jZSBmcm9tIHByb3Rlc3Qgc2l0ZXMgYW5kIHBvbGljZSBzdGF0aW9ucyBwcmVkaWN0cyBwcm90ZXN0IHByb3BlcnR5IGRhbWFnZSBiZXR0ZXIgdGhhbiBhIG1vZGVsIHRoYXQgaW5jbHVkZXMgb3RoZXIgdmFyaWFibGVzLg0KDQo8YnI+DQoNCiMjIFByZWRpY3Rpb24gQWNjdXJhY3kNCg0KYGBge3IgY29uZnVzaW9uIG1hdHJpeH0NCiNDcmVhdGUgZGF0YWZyYW1lIHRvIGhvbGQgcHJlZGljdGVkIHByb2JhYmlsaXRpZXMNCnByZWQgPC0gYXMuZGF0YS5mcmFtZShmaXR0ZWQobW9kMikpDQpwcmVkIDwtIG11dGF0ZShwcmVkLCAib2JzIiA9IGRhdCRkYW1hZ2VkKQ0KcHJlZCA8LSByZW5hbWUocHJlZCwgInByb2IiID0gImZpdHRlZChtb2QyKSIpDQpwcmVkIDwtIG11dGF0ZShwcmVkLCAicHJlZCIgPSBpZmVsc2UocHJvYiA8IDAuNSwgMCwgMSkpICNpZiBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcyBhcmUgPDAuNSwgdGhlbiBjbGFzc2lmeSBhcyB6ZXJvLCBvdGhlcndpc2UgY2xhc3NpZnkgYXMgMQ0KDQojQ3JlYXRlIGNvbmZ1c2lvbiBtYXRyaXgNCmNhcmV0Ojpjb25mdXNpb25NYXRyaXgocmVmZXJlbmNlID0gYXMuZmFjdG9yKHByZWQkb2JzKSwgDQogICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBhcy5mYWN0b3IocHJlZCRwcmVkKSwgDQogICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aXZlID0gIjEiKQ0KYGBgDQpDYWxjdWxhdGluZyBvdXIgbW9kZWwncyBwcmVkaWN0aW9uIGFjY3VyYWN5IGdpdmVzIHVzIGFuIGFjY3VyYWN5IHJhdGUgb2YgOTUlIC0gcHJldHR5IGdvb2QhIEJ1dCBpcyBpdCB0b28gZ29vZD8NCg0KV2Ugc2VlIHRoYXQgdGhlIG1vZGVsIGNvbnNpZGVyYWJseSB1bmRlciBwcmVkaWN0cyB0aGUgbGlrZWxpaG9vZCBvZiBhIGZpc2huZXQgY2VsbCBjb250YWluaW5nIGRhbWFnZWQgcHJvcGVydGllcy4gU28gdGhlIGFjY3VyYWN5IHJhdGUgc2F5cyBtb3JlIGFib3V0IHRoZSBzbWFsbCBzYW1wbGUgc2l6ZSBvZiBkYW1hZ2VkIHByb3BlcnRpZXMgdGhhbiB0aGUgZ2VuZXJhbGl6YWJpbGl0eSBvZiB0aGUgbW9kZWwuDQoNCg0KIyMgTWFwcGluZyBQcmVkaWN0aW9ucw0KYGBge3Iga19mb2xkLCByZXN1bHRzPSdoaWRlJ30NCg0KY3RybCA8LSB0cmFpbkNvbnRyb2wobWV0aG9kID0gImN2IiwgDQogICAgICAgICAgICAgICAgICAgICBudW1iZXIgPSAxMDAsIA0KICAgICAgICAgICAgICAgICAgICAgc2F2ZVByZWRpY3Rpb25zID0gVFJVRSkNCg0KZG1nRml0IDwtIHRyYWluKGFzLmZhY3RvcihkYW1hZ2VkKSB+IC4sDQogICAgICAgICAgICAgICBkYXRhID0gZGF0ICU+JSANCiAgICAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZSgpICU+JQ0KICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KGRhbWFnZWQsIGNtbXJjbF9zdW0sIGNtbXJjbF9iaW5hcnksIERJU1RfUFJUU1QsIERJU1RfUE9MQywgdmFsdWVfbG9nLA0KICAgICAgICAgICAgICAgIGFic250ZWVfc3VtLCBwY3RXaGl0ZV9tZWQpICU+JSANCiAgICAgICAgICAgICAgIG5hLm9taXQoKSwNCiAgICAgICAgICAgICAgIG1ldGhvZD0iZ2xtIiwgZmFtaWx5PSJiaW5vbWlhbCIsDQogICAgICAgICAgICAgICB0ckNvbnRyb2wgPSBjdHJsKQ0KZG1nRml0DQojaW51bmRGaXQgaXMgb3VyIG1vZGVsIHRyYWluZWQgdG8gcHJlZGljdCB1c2luZyB0aGUgYmlub21pYWwgbG9naXN0aWMgcmVncmVzc2lvbiwgb3IgZ2xtLCBtZXRob2QuIA0KYGBgDQoNCmBgYHtyIHByZWQgbWFwIHNldHVwLCByZXN1bHRzPSdoaWRlJ30NCmRhdF9tYXAgPC0gZGF0ICU+JSANCiAgZHBseXI6OnNlbGVjdCh1bmlxdWVJRCwgZGFtYWdlZCwgY21tcmNsX3N1bSwgY21tcmNsX2JpbmFyeSwgRElTVF9QUlRTVCwgRElTVF9QT0xDLCB2YWx1ZV9sb2csDQogICAgICAgICAgICAgICAgYWJzbnRlZV9zdW0sIHBjdFdoaXRlX21lZCwgZ2VvbWV0cnkpDQoNCmFsbFByZWRpY3Rpb25zIDwtIA0KICBwcmVkaWN0KGRtZ0ZpdCwgZGF0LCB0eXBlPSJwcm9iIilbLDJdDQogIA0KZGF0X3ByZWQgPC0gDQogIGNiaW5kKGRhdF9tYXAsIGFsbFByZWRpY3Rpb25zKSAlPiUNCiAgbXV0YXRlKGFsbFByZWRpY3Rpb25zID0gcm91bmQoYWxsUHJlZGljdGlvbnMgKiAxMDApKSANCg0KZGF0X3ByZWQgPC0gZGF0X3ByZWQgJT4lDQogIG11dGF0ZShjb25mUmVzdWx0PWNhc2Vfd2hlbihhbGxQcmVkaWN0aW9ucyA8IDUwICYgZGFtYWdlZD09MCB+ICJUcnVlIE5lZ2F0aXZlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbFByZWRpY3Rpb25zID49IDUwICYgZGFtYWdlZD09MSB+ICJUcnVlIFBvc2l0aXZlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbFByZWRpY3Rpb25zIDwgNTAgJiBkYW1hZ2VkPT0xIH4gIkZhbHNlIE5lZ2F0aXZlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbFByZWRpY3Rpb25zID49IDUwICYgZGFtYWdlZD09MCB+ICJGYWxzZSBQb3NpdGl2ZSIpKQ0KYGBgDQogDQoNCmBgYHtyIHByZWQgbWFwLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OH0NCmRhdF9wcmVkIDwtIGRhdF9wcmVkICU+JQ0KICBzdF90cmFuc2Zvcm0oY3JzID0gNjUwNSkNCg0KZ3JpZC5hcnJhbmdlKG5jb2wgPSAyLA0KIGdncGxvdCgpICsgDQogICAgZ2VvbV9zZihkYXRhPWRhdF9wcmVkLCBhZXMoZmlsbD1hbGxQcmVkaWN0aW9ucyksIA0KICAgICAgICAgICAgY29sb3VyPU5BKSArDQogICAgICBzY2FsZV9maWxsX3ZpcmlkaXMoDQogICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAuOCwNCiAgICAgICAgICAgICAgICAgICAgICBiZWdpbiA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgZW5kID0gMC45LA0KICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgZGlzY3JldGUgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBvcHRpb24gPSAiQiIsDQogICAgICAgICAgICAgICAgICAgICAgbmFtZT0iUHJlZGljdGVkXG5Qcm9iYWJpbGl0aWVzICglKSIpICsNCiAgbGFicyh0aXRsZT0iUHJlZGljdGVkIFByb2JhYmlsaXR5IG9mIFByb3BlcnR5IERhbWFnZSIsDQogICAgICAgc3VidGl0bGUgPSAiQmFzZWQgb24gYSBMb2dpc3RpYyBSZWdyZXNzaW9uIE1vZGVsIikgKw0KICAgICBtYXBUaGVtZSwNCiANCiBnZ3Bsb3QoKSsNCiAgZ2VvbV9zZihkYXRhPWRhdF9wcmVkLA0KICAgICAgICAgIGFlcyhmaWxsID0gY29uZlJlc3VsdCksIGNvbG9yID0gInRyYW5zcGFyZW50IiwgYWxwaGEgPSAuOCkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjNkIxODZFRkYiLCAiI0NDNDI0OEZGIiwgIiMwMDAwMDRGRiIsICIjRkNBNTBBRkYiKSwNCiAgICAgICAgICAgICAgICAgICAgbmFtZT0iT3V0Y29tZXMiKSsNCiAgbGFicyh0aXRsZT0iQ29uZnVzaW9uIE1ldHJpY3MiLA0KICAgICAgIHN1YnRpdGxlID0gIkJhc2VkIG9uIGEgUHJvYmFiaWxpdHkgPj0gNTAlIikgKw0KICBtYXBUaGVtZQ0KKQ0KYGBgDQpNYXBwaW5nIHdoZXJlIGFuZCBob3cgd2VsbCB0aGUgbW9kZWwgcHJlZGljdHMgcHJvdGVzdCBwcm9wZXJ0eSBkYW1hZ2Ugc2hvd3MgdGhhdCBob3cgdGhlIGN1dG9mZiBmb3IgcHJlZGljdGlvbiBhY2N1cmFjeSBpcyBkZWZpbmVkIGlzIHZlcnkgaW1wb3J0YW50LiBUaGUgbWFwIG9uIHRoZSBsZWZ0IG9mIHByZWRpY3RlZCBwcm9iYWJpbGl0aWVzIHNlZW1zIHRvIGNsb3NlbHkgcmVmbGVjdCB0aGUgYWN0dWFsIChvciBvYnNlcnZlZCkgcGF0dGVybnMgb2YgcHJvcGVydHkgZGFtYWdlLiBIb3dldmVyLCBtYXBwaW5nIHRoZSBjb25mdXNpb24gbWV0cmljcyBvbiB0aGUgcmlnaHQgd2l0aCBhIGN1dG9mZiBvZiA1MCUgcHJvYmFiaWxpdHkgY291bnRzIG1hbnkgb2YgdGhlIGNlbGxzIHRoYXQgYXJlIGhpZ2hsaWdodGVkIGluIG9yYW5nZSBvbiB0aGUgbGVmdGhhbmQgbWFwIGFzIGZhbHNlIG5lZ2F0aXZlcy4NCg0KQSA1MCUgcHJvYmFiaWxpdHkgdGhyZXNob2xkIGlzIGEgcmVhc29uYWJsZSB0aHJlc2hvbGQgZm9yIHByZWRpY3Rpb24gaG93ZXZlci4gU2luY2UgaXQgaXMgdW53aXNlIHRvIGNvdW50IGNlbGxzIHdpdGggYSBsZXNzIHRoYW4gNTAlIHByb2JhYmlsaXR5IG9mIGJlaW5nIGRhbWFnZWQgYXMgImxpa2VseSIgdG8gYmUgZGFtYWdlZC4NCg0KVGhlc2UgbWFwcyB2aXN1YWxseSByZWluZm9yY2UgdGhlIGNvbmNsdXNpb24gb2YgdGhlIGNvbmZ1c2lvbiBtYXRyaXguIE5hbWVseSwgdGhhdCB3aGlsZSB0aGUgbW9kZWwgZG9lcyBjYXB0dXJlIGJhc2ljIHBhdHRlcm5zIG9mIHByb3Rlc3QgcHJvcGVydHkgZGFtYWdlIGJhc2VkIG9uIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMgaW5jbHVkZWQgaW4gaXQsIGl0IGlzIHN0aWxsIG5vdCBhY2N1cmF0ZWx5IHByZWRpY3Rpbmcgb3ZlcmFsbC4gVGhpcyBzaG93cyB0aGF0IG1vcmUgdmFyaWFibGVzIGFuZCBmdXJ0aGVyIHRlc3RpbmcgYXJlIG5lZWRlZCB0byBiZXR0ZXIgdW5kZXJzdGFuZCB0aGUgcXVhbnRpdGF0aXZlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBwcm90ZXN0IHByb3BlcnR5IGRhbWFnZSBhbmQgZmFjdG9ycyByZWxhdGVkIHRvIGxhbmQgdXNlIGFuZCBzb2Npb2Vjb25vbWljIGdlb2dyYXBoaWMgdHJhaXRzLg0KDQo8YnI+DQoNCiMgTGltaXRhdGlvbnMNCg0KVGhlIGZpc2huZXQgbWV0aGRvbG9neSBzcGVlZHMgcHJvY2Vzc2luZywgYnV0IHNhY3JpZmljZXMgcHJlY2lzaW9uIGFuZCBtYWtlcyBpbnRlcnByZXRpbmcgdGhlIG1vZGVsJ3MgcmVzdWx0cyBzb21ld2hhdCBjb252b2x1dGVkLiBGb3IgZXhhbXBsZSwgd2l0aCB0aGUgZmlzaG5ldCBhcHByb2FjaCBpdCBpcyBub3QgcG9zc2libGUgdG8gY3JlYXRlIGEgdHJ1ZSBiaW5hcnkgdmFyaWFibGUgZm9yIGNvbW1lcmNpYWwgdnMuIG5vbi1jb21tZXJjaWFsIHByb3BlcnRpZXMgYXMgaXQgd291bGQgYmUgaWYgc2ltcGx5IHJ1bm5pbmcgcmVncmVzc2lvbnMgb24gdGhlIHBhcmNlbHMgdGhlbXNlbHZlcy4gSW5zdGVhZCwgdGhlIGFyZWEgb2YgZGFtYWdlZCBwcm9wZXJ0aWVzIGhhZCB0byBiZSBzdW1tZWQgYnkgZmlzaG5ldCBncmlkIGNlbGwgYXMgYW4gYXBwcm94aW1hdGlvbi4NCg0KSW4gYW5vdGhlciBpdGVyYXRpb24gb2YgdGhlIHByb2plY3QsIGl0IHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIHNlZSBpZiBoYXZpbmcgc21hbGxlciBncmlkIGNlbGxzIGNvdWxkIGltcHJvdmUgdGhlIHJlc3VsdHMuIEZvciBleGFtcGxlLCBhIGRpYW1ldGVyIG9mIDE2MCcgd291bGQgZ2l2ZSBmb3VyIHRpbWVzIHRoZSBudW1iZXIgb2YgY2VsbHMuIEl0IHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIHNlZSBpZiBSIGNvdWxkIHN0aWxsIGVmZmljaWVudGx5IHByb2Nlc3MgYSBkYXRhZnJhbWUgb2YgMTYsMDAwLiBUaGlzIHdvdWxkIGJlIGEgYmlnIGluY3JlYXNlIGZyb20gdGhlIDQsMDAwIHVzZWQgaW4gdGhpcyBwcm9qZWN0LCBidXQgd291bGQgc3RpbGwgYmUgYSBzaWduaWZpY2FudGx5IHNtYWxsZXIgZGF0YXNldCB0aGFuIHRoZSAxMzAsMDAwIHBhcmNlbHMgd2l0aGluIE1pbm5lYXBvbGlzIGNpdHkgbGltaXRzLg0KDQpBbm90aGVyIGxpbWl0YXRpb24gb2YgdGhpcyBzdHVkeSBpcyB0aGUgY291cnNlIGRlZmluaXRpb24gb2YgYWJzZW50ZWUgb3duZXJzaGlwLiBJZGVhbGx5LCB0aGUgYWJzZW50ZWUgb3duZXJzaGlwIHZhcmlhYmxlIHdvdWxkIGJlIGFibGUgdG8gYWNjb3VudCBmb3IgbW9yZSBudWFuY2UgdGhhbiB0aGUgc2ltcGxlIGRpc3RpbmN0aW9uIG9mIHdoZXRoZXIgb3Igbm90IHRoZSBwcmltYXJ5IHRheHBheWVyJ3MgYWRkcmVzcyB3YXMgaW4gY2l0eSBib3VuZGFyaWVzLiBJZGVhbGx5LCBhIHByb3BlcnR5J3MgZGlzdGFuY2UgZnJvbSBpdHMgcHJpbWFyeSB0YXhwYXllciB3b3VsZCBiZSB1c2VkIGluc3RlYWQuIFRoaXMgd291bGQgY2FwdHVyZSBhIG11Y2ggbW9yZSBkZXRhaWxlZCBhbmQgY29uc2lzdGVudCByZWxhdGlvbnNoaXAuIEhvd2V2ZXIsIGRvaW5nIHNvIGZvciBldmVyeSBwYXJjZWwgaW4gTWlubmVhcG9saXMgZXhjZWVkZWQgdGhlIHRpbWUgYW5kIHByb2Nlc3NpbmcgcG93ZXIgYXZhaWxhYmxlIGZvciB0aGlzIHByb2plY3QuDQoNCk5vdyB0aGF0IHRoaXMgcHJvamVjdCBoYXMgZXN0YWJsaXNoZWQgYSBzaWduaWZpY2FudCByZWxhdGlvbnNoaXAgYmV0d2VlbiBkYW1hZ2VkIHByb3BlcnRpZXMgYW5kIGNvbW1lcmNpYWwgbGFuZCB1c2UsIGEgbG9naWNhbCBuZXh0IHN0ZXAgaXMgdG8gZXhhbWluZSB3aGljaCBraW5kcyBvZiBidXNpbmVzc2VzIHdlcmUgbW9zdCBkYW1hZ2VkLiBOb3QgaGF2aW5nIGJ1c2luZXNzIHR5cGUgZGF0YSBhdCB0aGUgcHJvcGVydHkgcGFyY2VsIGxldmVsIGlzIGEgbGltaXRhdGlvbiBvZiB0aGlzIHN0dWR5Lg0KDQpUaGUgbGFyZ2UgY29lZmZpY2llbnQgb2YgdGhlIGludGVyY2VwdCBoaWdobGlnaHRzIHRoYXQgbW9yZSB2YXJpYWJsZXMgYXJlIG5lY2Vzc2FyeSB0byBhY2N1cmF0ZWx5IG1vZGVsIHRoZSBkYXRhLiBPdGhlciB2YXJpYWJsZXMgdG8gaW5jbHVkZSBpbiBmdXR1cmUgd29yaywgaW4gYWRkaXRpb24gdG8gYnVzaW5lc3MgdHlwZSwgYXJlIG1vcmUgcmljaCBzb2Npb2Vjb25vbWljIGFuZCBsYW5kLXVzZSBkZXNjcmlwdG9ycy4gRm9yIGV4YW1wbGUsIGlzIHRoZSBpbXBvcnRhbmNlIG9mIGNvbW1lcmNpYWwgY29ycmlkb3JzIGluIHRoZSBtb2RlbCBiZWNhdXNlIG9mIGRlbnNpdHkgb2Ygc3RvcmVzIG9yIHNvbWV0aGluZyBlbHNlPyBBbmQsIGhvdyBtaWdodCB0aGUgaWRlbnRpdHkgb2YgYWZmZWN0ZWQgYXJlYXMsIHRoZWlyIHJlbGF0aW9uc2hpcCB0byB0aGUgY2l0eSdzIHBvd2VyIHN0cnVjdHVyZXMsIGFuZCB0aGUgY29tbXVuaXRpZXMgdGhhdCB3YXRjaGVkIG92ZXIgdGhlbSByZWxhdGUgdG8gbGV2ZWwgb2YgZGFtYWdlIHJlY2VpdmVkPyBNb2JpbGl0eSBjb3VsZCBhbHNvIGJlIGFuIGltcG9ydGFudCBmYWN0b3IuIE1pZ2h0IHRyYW5zaXQgYWNjZXNzIGFuZCB3YWxrYWJpbGl0eSBoYXZlIHBvc2l0aXZlbHkgY29ycmVsYXRlZCB3aXRoIHByb3Rlc3QgZGFtYWdlPw0KDQpGaW5hbGx5LCB0aGlzIGlzIG5vdCBhIHN0b3J5IG9mIG51bWJlcnMuIElkZWFsbHkgYSBwcm9qZWN0IGxpa2UgdGhpcyB3b3VsZCBiZSBwcm92aWRpbmcgZGF0YSB0aGF0IHN1cHBvcnRzIG9yIGFkZHMgbnVhbmNlIHRvIGEgcm9idXN0IHF1YWxpdGF0aXZlIHJlc2VhcmNoIHByb2plY3QgdGhhdCBjZW50ZXJzIHRoZSBzdG9yaWVzIG9mIHRob3NlIG1vc3QgYWZmZWN0ZWQgYnkgR2VvcmdlIEZsb3lkJ3MgbXVyZGVyIGF0IHRoZSBoYW5kcyBvZiB0aGUgTWlubmVhcG9saXMgUG9saWNlIERlcGFydG1lbnQgYW5kIHRoZSBkZXN0cnVjdGlvbiB0aGF0IGZvbGxvd2VkLg0KDQo8YnI+DQoNCiMgUGxhbm5pbmcgSW1wbGljYXRpb25zDQoNClRoaXMgcHJvamVjdCBzaG93cyB0aGF0IHRoZSBwcm9wZXJ0eSBkYW1hZ2UgcmVsYXRlZCB0byB0aGUgcHJvdGVzdHMgYWdhaW5zdCBHZW9yZ2UgRmxveWQncyBtdXJkZXIgaW4gTWlubmVhcG9saXMgaW4gMjAyMCB3YXMgbm90IHNpbXBseSBhIG1hdHRlciBvZiBwcm94aW1pdHkgdG8gcHJvdGVzdCBzaXRlcy4gSW5zdGVhZCwgaXQgaW5kaWNhdGVzIHRoYXQgY29tbWVyY2lhbCBjb3JyaWRvcnMgd2VyZSBzaWduaWZpY2FudCBsb2NhdGlvbnMgb2YgcHJvdGVzdCBkYW1hZ2UgYW5kIHByb3Rlc3QgZGFtYWdlIGluIFdoaXRlIGVuY2xhdmVzIHdhcyBjb25zcGljaW91c2x5IGFic2VudC4NCg0KV2hpbGUgdGhlIHByZXNlbmNlIG9mIGNvbW1lcmNpYWwgKnByb3BlcnRpZXMqIHdhcyByZWxhdGVkIHRvIHByb3Rlc3QgZGFtYWdlIHdpdGggc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlLCBpdCBpcyBub3Rld29ydGh5IHRoYXQgbG9jYXRpb24gb24gYSBjb21tZXJjaWFsIGNvcnJpZG9yIHdhcyBhIG11Y2ggc3Ryb25nZXIgcHJlZGljdG9yIG9mIGRhbWFnZS4gVGhpcyBzdWdnZXN0cyB0aGF0IHBlcmNlcHRpb24gb2YgcHVibGljIHNwYWNlIG1heSBoYXZlIGEgc3Ryb25nZXIgZWZmZWN0IHRoYW4gaXRzIGFjdHVhbCB1c2UuIEl0IGFsc28gZW1waGFzaXplcyB0aGF0IGNvbW1lcmNpYWwgY29ycmlkb3JzIGFyZSBrZXkgbm9kZXMgb2YgcHVibGljIGV4cHJlc3Npb24gYW5kIGlkZW50aXR5IGluIHVyYmFuIGVudmlyb25tZW50cy4gSW4gcGFydGljdWxhciwgdGhlIHJlc3VsdHMgb2YgdGhpcyByZXNlYXJjaCBzdWdnZXN0IHRoYXQgd2hlbiBwcm90ZXN0ZXJzIHN0cnVnZ2xlIGZvciBhZ2VuY3kgaW4gYSBjYXBpdGFsaXN0IHNvY2lldHkgd2hlcmUgY29tbWVyY2UgYW5kIHBvd2VyIGFyZSBkZWVwbHkgaW50ZXJ3b3ZlbiwgdGhlIGNvbW1lcmNpYWwgY29ycmlkb3JzIG9mIHNvY2lldHkgaXRzZWxmIGFyZSBsaWtlbHkgdG8gYmVjb21lIGNvbnRlc3RlZCBncm91bmQuIFRoZXJlZm9yZSwgcGxhbm5lcnMgd291bGQgZG8gd2VsbCB0byBzdXBwb3J0IGluaXRpYXRpdmVzIHRoYXQgc3RyZW5ndGhlbiBjb21tdW5pdHkgaWRlbnRpdHkgYW5kIHByb3ZpZGUgc3BhY2VzIGZvciBtb3ZlbWVudCBidWlsZGluZyBvbiBjb21tZXJjaWFsIGNvcnJpZG9ycy4gQXJndWFibHksIHRoZSBNaW5uZWFwb2xpcyBwdWJsaWMgZGlkIG5vdCBoYXZlIGVub3VnaCBjb25zdHJ1Y3RpdmUgYXZlbnVlcyBmb3IgY2l0eSBsZWFkZXJzIHRvIGhlYXIgYW5kIHJlc3BvbmQgdG8gdGhlaXIgYW5nZXIgaW4gMjAyMC4gVGhpcyByZXNlYXJjaCBzdWdnZXN0cyB0aGF0IGNvbW1lcmNpYWwgY29ycmlkb3JzIGFyZSBrZXkgc2l0ZXMgZm9yIGNpdHkgcGxhbm5lcnMgdG8gcHJvdmlkZSBvciBlbmNvdXJhZ2UgYWNjZXNzaWJsZSBhbmQgbWVhbmluZ2Z1bCBjb25uZWN0aW9ucyBiZXR3ZWVuIHRoZSBwdWJsaWMgYW5kIGNpdmljIHBvd2VyIHN0cnVjdHVyZXMuDQoNClNpbWlsYXJseSwgdGhlIGZhY3QgdGhhdCB0aGUgc2hhcmUgb2YgV2hpdGUgcG9wdWxhdGlvbiBpbiBhbiBhcmVhIGhhZCBhIHNpZ25pZmljYW50IG5lZ2F0aXZlIHJlbGF0aW9uc2hpcCB3aXRoIHByb3Rlc3QgZGFtYWdlIHNwZWFrcyB0byB0aGUgaWRlbnRpdHkgb2YgYSBwbGFjZSBiZWluZyBhbiBpbXBvcnRhbnQgZmFjdG9yIGR1cmluZyB0aGUgTWlubmVhcG9saXMgcHJvdGVzdHMgb2YgMjAyMC4gSXQgbGVuZHMgc3RhdGlzdGljYWwgd2VpZ2h0IHRvIHRoZSBpZGVhIHRoYXQgdGhlIHJhY2lhbCBhbmQgZWNvbm9taWMgc2VncmVnYXRpb24gb2YgVS5TLiBjaXRpZXMgdGhhdCBoYXMgaGlzdG9yaWNhbGx5IGNvbmNlbnRyYXRlZCBhZmZsdWVuY2UgYW5kIHBvd2VyIGluIGxhcmdlbHkgV2hpdGUgbmVpZ2hib3Job29kcyBtYXkgYWxzbyBoYXZlIGNvbmNlbnRyYXRlZCBwcm90ZXN0cyB3aXRoaW4gdGhlIGNpdHkncyBlY29ub21pY2FsbHkgb3IgcmFjaWFsbHkgbWFyZ2luYWxpemVkIGNvbW11bml0aWVzLiBJdCBpcyBpbXBvcnRhbnQgdG8gcmVjb2duaXplIHRoYXQgV2hpdGUgYW5kIEJJUE9DIE1pbm5lYXBvbGl0YW5zIGRpZCBub3QgZXF1YWxseSBzdWZmZXIgdGhlIGNvbnNlcXVlbmNlcyBvZiBkZXN0cnVjdGlvbiBmb2xsb3dpbmcgdGhlIHByb3Rlc3RzLiBUaGVyZWZvcmUsIGNpdHkgcGxhbm5lcnMgaGF2ZSBhbiBpbXBlcmF0aXZlIHRvIGNvbmNlbnRyYXRlIGVmZm9ydHMgYXQgcmVidWlsZGluZyBhbmQgcmVjb25jaWxpYXRpb24gaW4gYXJlYXMgd2l0aCBsb3cgc2hhcmVzIG9mIFdoaXRlIHJlc2lkZW50cy4NCg0KV2hpbGUgdGhlIGNvZWZmaWNpZW50cyBmb3IgYWJzZW50ZWUgb3duZXJzaGlwIGFuZCBwcm9wZXJ0eSB2YWx1ZSB3ZXJlIHNtYWxsLCB0aGV5IHNob3cgdGhhdCB0aGVzZSB3ZXJlIGFsc28gc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBmYWN0b3JzIGR1cmluZyB0aGUgcHJvdGVzdHMuIFRoZSBmYWN0IHRoYXQgYWJzZW50ZWUgb3duZXJzaGlwIGlzIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCB2YXJpYWJsZSBsZW5kcyBjcmVkZW5jZSB0byBhIGNvbW1vbiBuYXJyYXRpdmUgYW1vbmcgcHJvdGVzdG9ycyB0aGF0IHByb3BlcnR5IGRhbWFnZSB3YXMgYW4gZXhwcmVzc2lvbiBvZiBhbmdlciBhbmQgZnJ1c3RyYXRpb24gdGFyZ2V0ZWQgYXQgY2FwaXRhbGlzdCBwb3dlciBzdHJ1Y3R1cmVzIHJhdGhlciB0aGFuIGxvY2FsIGJ1c2luZXNzIG93bmVycy4gVGhlIHNsaWdodCBjb3JyZWxhdGlvbiBiZXR3ZWVuIHByb3BlcnR5IGRhbWFnZSBhbmQgaGlnaCBwcm9wZXJ0eSB2YWx1ZSBmdXJ0aGVyIHN1cHBvcnRzIHRoaXMgaHlwb3RoZXNpcy4gVG9nZXRoZXIsIHRoZXNlIGZhY3RvcnMgc3VnZ2VzdCB0aGF0IHN1cHBvcnRpbmcgYW5kIGluY3JlYXNpbmcgYWNjZXNzIHRvIGxvY2FsIGJ1c2luZXNzIG93bmVyc2hpcCBjb3VsZCBoYXZlIGEgbG9uZy10ZXJtIHN0YWJpbGl6aW5nIGVmZmVjdCBpbiBjaXRpZXMuIEluY3JlYXNpbmcgYWNjZXNzIHRvIGxvY2FsIG93bmVyc2hpcCBvZiBoaWdoIHZhbHVlIHByb3BlcnR5IHBlcmhhcHMgZXZlbiBtb3JlIHNvLg0KDQpUaGVzZSBvYnNlcnZhdGlvbnMgYXJlIG1lYW50IHRvIGJlIGV4cGxvcmF0b3J5IHJhdGhlciB0aGFuIGRlZmluaXRpdmUuIEkgaG9wZSB0aGlzIHBpZWNlIGNhbiBzZXJ2ZSBhcyBhIGp1bXBpbmcgb2ZmIHBvaW50IGZvciB0aG9zZSBjb250aW51aW5nIHRoZSBzdHVkeSBvZiBzcGF0aWFsIGNoYXJhY3RlcmlzdGljcyBvZiBwcm90ZXN0IGluIE1pbm5lYXBvbGlzLg0KDQo8YnI+DQo8YnI+DQoNCiMgUmVmZXJlbmNlcw0KDQoxLiBCb29uZSwgQW5uYS4g4oCcT25lIFdlZWsgaW4gTWlubmVhcG9saXMu4oCdIFN0YXIgVHJpYnVuZS4gSnVuZSAzLCAyMDIwLiAgICAgICAgICAgICAgICAgICAgIA0KaHR0cHM6Ly93d3cuc3RhcnRyaWJ1bmUuY29tL2dlb3JnZS1mbG95ZC1kZWF0aC1pZ25pdGVkLXByb3Rlc3RzLWZhci1iZXlvbmQtbWlubmVhcG9saXMtcG9saWNlLW1pbm5lc290YS81Njk5MzA3NzEvLg0KDQoyLiBCYWtzdCwgQnJpYW4uIOKAnEd1YXJkIE1vYmlsaXplZCBRdWlja2x5LCBBZGp1c3RlZCBvbiBGbHkgZm9yIEZsb3lkIFVucmVzdC7igJ0gTVBSIE5ld3MsIEp1bHkgMTAsIDIwMjAuIGh0dHBzOi8vd3d3Lm1wcm5ld3Mub3JnL3N0b3J5LzIwMjAvMDcvMTAvZ3VhcmQtbW9iaWxpemVkLXF1aWNrbHktYWRqdXN0ZWQtb24tZmx5LWZvci1mbG95ZC11bnJlc3QuDQoNCjMuIFNjaG5laWRlciwgQ2F0aHkgTGlzYS4gMjAxNy4gUG9saWNlIFBvd2VyIGFuZCBSYWNlIFJpb3RzOiBVcmJhbiBVbnJlc3QgaW4gUGFyaXMgYW5kIE5ldyBZb3JrLg0KUmVwcmludCBlZGl0aW9uLiBQaGlsYWRlbHBoaWEsIFBhOiBVbml2ZXJzaXR5IG9mIFBlbm5zeWx2YW5pYSBQcmVzcy4NCg0KNC4gU3ByaW5nZXIsIFNpbW9uLiDigJxQdWJsaWMgU3BhY2UgYXMgRW1hbmNpcGF0aW9uOiBNZWRpdGF0aW9ucyBvbiBBbmFyY2hpc20sIFJhZGljYWwgRGVtb2NyYWN5LCBOZW9saWJlcmFsaXNtIGFuZCBWaW9sZW5jZS7igJ0gQW50aXBvZGUgNDMsIG5vLiAyICgyMDExKTogNTI14oCTNjIuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMTExL2ouMTQ2Ny04MzMwLjIwMTAuMDA4MjcueC4NCg0KNS4gTWNEb25hZ2gsIEJyaW9ueSwgYW5kIENhcmwgSi4gR3JpZmZpbi4g4oCcT2NjdXB5ISBIaXN0b3JpY2FsIEdlb2dyYXBoaWVzIG9mIFByb3BlcnR5LCBQcm90ZXN0IGFuZCB0aGUgQ29tbW9ucywgMTUwMOKAkzE4NTAu4oCdIEpvdXJuYWwgb2YgSGlzdG9yaWNhbCBHZW9ncmFwaHkgNTMgKEp1bHkgMSwgMjAxNik6IDHigJMxMC4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTYvai5qaGcuMjAxNi4wMy4wMDIuDQoNCjYuIFNhbG1lbmthcmksIFRhcnUuIOKAnEdlb2dyYXBoeSBvZiBQcm90ZXN0OiBQbGFjZXMgb2YgRGVtb25zdHJhdGlvbiBpbiBCdWVub3MgQWlyZXMgYW5kIFNlb3VsLuKAnSBVcmJhbiBHZW9ncmFwaHkgMzAsIG5vLiAzIChBcHJpbCAxLCAyMDA5KTogMjM54oCTNjAuIGh0dHBzOi8vZG9pLm9yZy8xMC4yNzQ3LzAyNzItMzYzOC4zMC4zLjIzOS4NCg0KNy4gU21pbGVzLCBEZW9uZHJlLiDigJxHZW9yZ2UgRmxveWQsIE1pbm5lYXBvbGlzLCBhbmQgU3BhY2VzIG9mIEhvcGUgYW5kIExpYmVyYXRpb24u4oCdIERpYWxvZ3VlcyBpbiBIdW1hbiBHZW9ncmFwaHkgMTEsIG5vLiAyIChKdWx5IDEsIDIwMjEpOiAxNjXigJM2OS4gaHR0cHM6Ly9kb2kub3JnLzEwLjExNzcvMjA0MzgyMDYyMTEwMjc0NjYuDQoNCjguIEZ1bGxpbG92ZSwgTSBULiDigJxDb21tZW50OiBBYmFuZG9uaW5nIOKAmFJhY2XigJkgYXMgYSBWYXJpYWJsZSBpbiBQdWJsaWMgSGVhbHRoIFJlc2VhcmNoLS1hbiBJZGVhIFdob3NlIFRpbWUgSGFzIENvbWUu4oCdIEFtZXJpY2FuIEpvdXJuYWwgb2YgUHVibGljIEhlYWx0aCA4OCwgbm8uIDkgKFNlcHRlbWJlciAxOTk4KTogMTI5N+KAkzk4Lg0KDQo=